The tasks included in this report are:

unique(measure_labels$task_group)
 [1] "adaptive_n_back"             "attention_network_task"     
 [3] "choice_reaction_time"        "directed_forgetting"        
 [5] "dot_pattern_expectancy"      "local_global_letter"        
 [7] "motor_selective_stop_signal" "recent_probes"              
 [9] "shape_matching"              "simon"                      
[11] "stim_selective_stop_signal"  "stop_signal"                
[13] "stroop"                      "threebytwo"                 
adaptive_n_back

attention_network_task

choice_reaction_time

directed_forgetting

dot_pattern_expectancy

local_global_letter

motor_selective_stop_signal

recent_probes

shape_matching

simon

stim_selective_stop_signal

stop_signal

stroop

threebytwo

T1 HDDM parameters

Before going on with the rest of the report first decide on whether there are significant differences in the distributions of the HDDM parameter estimates and their reliabilities depending on whether they are fit on the full sample (n=552) or retest sample (n=150) for t1 data.

Parameter stability

Differences in distributions: using scaled differences

Does the distribution of scaled difference scores (between using n=150 or n=552) have a mean different than 0 allowing for random effects of parameter accounting for the different types of parameters? No.

if(!exists('hddm_pars')){
  source('/Users/zeynepenkavi/Dropbox/PoldrackLab/SRO_DDM_Analyses/code/workspace_scripts/hddm_pars_data.R')
}
summary(lmer(scaled_diff ~ rt_acc + (1|dv), hddm_pars))
Linear mixed model fit by REML ['lmerMod']
Formula: scaled_diff ~ rt_acc + (1 | dv)
   Data: hddm_pars

REML criterion at convergence: 41695

Scaled residuals: 
    Min      1Q  Median      3Q     Max 
-10.438  -0.542  -0.004   0.518   9.750 

Random effects:
 Groups   Name        Variance Std.Dev.
 dv       (Intercept) 3.24e-33 5.69e-17
 Residual             9.93e-01 9.97e-01
Number of obs: 14722, groups:  dv, 103

Fixed effects:
                    Estimate Std. Error t value
(Intercept)         6.82e-18   9.82e-03       0
rt_accnon-decision -2.70e-17   2.44e-02       0
rt_accthreshold     9.98e-18   2.25e-02       0

Correlation of Fixed Effects:
            (Intr) rt_cc-
rt_ccnn-dcs -0.403       
rt_ccthrshl -0.436  0.176
# Same result
# summary(MCMCglmm(scaled_diff ~ rt_acc, random = ~ dv, data=hddm_pars))

Parameter reliability

Are there differences in reliability depending which sample the HDDM parameters are estimated from? No.

Do hddm parameters differ in their reliability depending on whether they are derived from n=150 or n=552? No.

if(!exists('hddm_rels')){
  source('/Users/zeynepenkavi/Dropbox/PoldrackLab/SRO_DDM_Analyses/code/workspace_scripts/hddm_rel_data.R')}

hddm_rels = hddm_rels %>%
  gather(sample, value, -dv, -rt_acc)

summary(lmer(value ~ sample*rt_acc + (1|dv), hddm_rels))
Linear mixed model fit by REML ['lmerMod']
Formula: value ~ sample * rt_acc + (1 | dv)
   Data: hddm_rels

REML criterion at convergence: -1207

Scaled residuals: 
   Min     1Q Median     3Q    Max 
-3.492 -0.260  0.013  0.254  3.510 

Random effects:
 Groups   Name        Variance Std.Dev.
 dv       (Intercept) 0.029746 0.172   
 Residual             0.000196 0.014   
Number of obs: 440, groups:  dv, 220

Fixed effects:
                               Estimate Std. Error t value
(Intercept)                     0.50848    0.01642   30.96
samplerefit                    -0.00331    0.00188   -1.76
rt_accnon-decision              0.03807    0.02889    1.32
rt_accthreshold                -0.02978    0.02836   -1.05
samplerefit:rt_accnon-decision -0.00394    0.00331   -1.19
samplerefit:rt_accthreshold     0.00497    0.00325    1.53

Correlation of Fixed Effects:
            (Intr) smplrf rt_cc- rt_cct smp:_-
samplerefit -0.057                            
rt_ccnn-dcs -0.568  0.033                     
rt_ccthrshl -0.579  0.033  0.329              
smplrft:r_-  0.033 -0.568 -0.057 -0.019       
smplrft:rt_  0.033 -0.579 -0.019 -0.057  0.329

Parameter fit

Do HDDM parameter estimates fit participant data better if the model prior is informed by a larger sample? To assess model fit we sampled from the posterior predictive for each subject and regressed the predicted RT’s on actual RT’s (using both raw RT’s as well as log-transformed RT’s). Our measure of fit is the (adjusted) \(R^2\) from these regressions for each participant.

Here we compare model fits between the same model using a prior using n=552 vs n=150.

Note: In calculating the fit statistics for the full sample (n=552) hierarchical models we used fewer samples from the posterior predictive due to computational constraints. We did, however, confirm that the number of samples from the posterior predictive did not have an effect on the fit statistics. Details of those analyses can be found here.

refit_fitstats %>%
  left_join(t1_hierarchical_fitstats, by = c("subj_id", "task_name")) %>%
  ggplot(aes(log_rsq_adj.x, log_rsq_adj.y))+
  geom_point(aes(color=task_name))+
  xlab("Adjusted r-sq for n=150")+
  ylab("Adjusted r-sq for n=552")+
  theme(legend.position = "none")+
  geom_abline(slope = 1, intercept=0)
Warning: Column `subj_id` joining factors with different levels, coercing
to character vector
Warning: Removed 106 rows containing missing values (geom_point).

The fit statistics (looking here at the adjusted \(R^2\)s using log-transformed RT’s) for the same models using n=552 and n=150 for the priors are highly correlated.

tmp = refit_fitstats %>%
  left_join(t1_hierarchical_fitstats, by = c("subj_id", "task_name"))
Warning: Column `subj_id` joining factors with different levels, coercing
to character vector
with(tmp, cor.test(log_rsq_adj.x, log_rsq_adj.y))

    Pearson's product-moment correlation

data:  log_rsq_adj.x and log_rsq_adj.y
t = 120, df = 1900, p-value <2e-16
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
 0.9317 0.9425
sample estimates:
   cor 
0.9373 

And they do not systematically differ from each other.

with(tmp, t.test(log_rsq_adj.x, log_rsq_adj.y, paired=T))

    Paired t-test

data:  log_rsq_adj.x and log_rsq_adj.y
t = -1.1, df = 1900, p-value = 0.3
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
 -0.0006482  0.0001833
sample estimates:
mean of the differences 
             -0.0002325 

Conclusion: Parameter estimates from refits to retest sample only for t1 data do not differ in any detectable way from estimates using the full t1 sample. They are also in principle more comparable to the parameter estimates from t2 and therefore used in the rest of this report.

DDM vs raw reliability overall

Plot reliability point estimates comparing DDM measures to raw measures faceting for contrast measures.

fig_name = 'ddmvsraw_point.jpeg'

knitr::include_graphics(paste0(fig_path, fig_name))

Plot averaged bootstrapped reliability estimates per measure comparing DDM measures to raw measures faceting for contrast measures.

fig_name = 'ddmvsraw_boot.jpeg'

knitr::include_graphics(paste0(fig_path, fig_name))

Model testing if the reliability of raw measures differs from that of ddm estimates and if contrast measures differ from non-contrast measures.

Checking if both fixed effects of raw vs ddm and contrast vs non-contrast as well as their interaction is necessary.

Conclusion: Interactive model is best.

mer1 = lmer(icc ~ ddm_raw + (1|dv), boot_df %>% filter(rt_acc != "other"))
mer1a = lmer(icc ~ overall_difference + (1|dv), boot_df %>% filter(rt_acc != "other"))
mer2 = lmer(icc ~ ddm_raw + overall_difference + (1|dv), boot_df %>% filter(rt_acc != "other"))
mer3 = lmer(icc ~ ddm_raw * overall_difference + (1|dv), boot_df %>% filter(rt_acc != "other"))
anova(mer1, mer2, mer3)
refitting model(s) with ML (instead of REML)
anova(mer1a, mer2, mer3)
refitting model(s) with ML (instead of REML)
rm(mer1, mer2, mer1a)

Raw measures do not significantly differ from ddm parameters in their reliability but non-contrast measures are significantly more reliable compared to contrast and condition measures.

summary(mer3)
Linear mixed model fit by REML ['lmerMod']
Formula: icc ~ ddm_raw * overall_difference + (1 | dv)
   Data: boot_df %>% filter(rt_acc != "other")

REML criterion at convergence: -654256

Scaled residuals: 
    Min      1Q  Median      3Q     Max 
-130.34   -0.36    0.03    0.40   17.35 

Random effects:
 Groups   Name        Variance Std.Dev.
 dv       (Intercept) 0.0518   0.228   
 Residual             0.0162   0.127   
Number of obs: 512000, groups:  dv, 512

Fixed effects:
                                       Estimate Std. Error t value
(Intercept)                              0.5947     0.0245   24.23
ddm_rawraw                              -0.0329     0.0395   -0.83
overall_differencecontrast              -0.3660     0.0366   -9.99
overall_differencecondition             -0.0865     0.0304   -2.84
ddm_rawraw:overall_differencecontrast    0.0790     0.0597    1.32
ddm_rawraw:overall_differencecondition  -0.0743     0.0490   -1.52

Correlation of Fixed Effects:
                        (Intr) ddm_rw ovrll_dffrnccnt ovrll_dffrnccnd
ddm_rawraw              -0.621                                       
ovrll_dffrnccnt         -0.670  0.416                                
ovrll_dffrnccnd         -0.806  0.501  0.540                         
ddm_rwrw:vrll_dffrnccnt  0.411 -0.662 -0.614          -0.331         
ddm_rwrw:vrll_dffrnccnd  0.501 -0.807 -0.336          -0.621         
                        ddm_rwrw:vrll_dffrnccnt
ddm_rawraw                                     
ovrll_dffrnccnt                                
ovrll_dffrnccnd                                
ddm_rwrw:vrll_dffrnccnt                        
ddm_rwrw:vrll_dffrnccnd  0.534                 

Best measure for each task

What is the best measure of individual difference for any measure that has both raw and DDM parameters?

Even though overall the ddm parameters are not significantly less reliable the most reliable measure is more frequently a raw measure. There are some examples of an EZ estimate being the best for a task as well. Regardless of raw vs ddm the best measure is always a non-contrast measure.

rel_df %>%
  group_by(task_group) %>%
  filter(icc == max(icc)) %>%
  select(task_group, everything())

Variance breakdown measure types

fig_name = 'ddmvsraw_varsubs.jpeg'

knitr::include_graphics(paste0(fig_path, fig_name))

fig_name = 'ddmvsraw_varresid.jpeg'

knitr::include_graphics(paste0(fig_path, fig_name))

Model testing if the percentage of between subjects variance of raw measures differs from that of ddm estimates and if contrast measures differ from non-contrast measures.

Checking if both fixed effects of raw vs ddm and contrast vs non-contrast as well as their interaction is necessary.

Conclusion: Model with fixed effects for both is best.

mer1 = lmer(var_subs_pct ~ ddm_raw + (1|dv), boot_df %>% filter(rt_acc != "other"))
mer1a = lmer(var_subs_pct ~ overall_difference + (1|dv), boot_df %>% filter(rt_acc != "other"))
mer2 = lmer(var_subs_pct ~ ddm_raw +  overall_difference + (1|dv), boot_df %>% filter(rt_acc != "other"))
mer3 = lmer(var_subs_pct ~ ddm_raw *  overall_difference + (1|dv), boot_df %>% filter(rt_acc != "other"))
anova(mer1, mer2, mer3)
refitting model(s) with ML (instead of REML)
anova(mer1a, mer2, mer3)
refitting model(s) with ML (instead of REML)
rm(mer1, mer1a, mer3)

Contrast measures have lower between subjects variability (ie are worse individual difference measures). Raw and ddm measures do not differ significantly.

summary(mer2)
Linear mixed model fit by REML ['lmerMod']
Formula: var_subs_pct ~ ddm_raw + overall_difference + (1 | dv)
   Data: boot_df %>% filter(rt_acc != "other")

REML criterion at convergence: 3845550

Scaled residuals: 
   Min     1Q Median     3Q    Max 
-4.485 -0.657  0.065  0.669  4.841 

Random effects:
 Groups   Name        Variance Std.Dev.
 dv       (Intercept) 197      14.0    
 Residual             106      10.3    
Number of obs: 512000, groups:  dv, 512

Fixed effects:
                            Estimate Std. Error t value
(Intercept)                    50.59       1.29    39.4
ddm_rawraw                      2.30       1.28     1.8
overall_differencecontrast     -8.02       1.78    -4.5
overall_differencecondition    -2.57       1.47    -1.7

Correlation of Fixed Effects:
                (Intr) ddm_rw ovrll_dffrnccnt
ddm_rawraw      -0.383                       
ovrll_dffrnccnt -0.619  0.012                
ovrll_dffrnccnd -0.745 -0.001  0.536         

Model testing if the percentage of residual variance of raw measures differs from that of ddm estimates and if contrast measures differ from non-contrast measures.

Checking if both fixed effects of raw vs ddm and contrast vs non-contrast as well as their interaction is necessary.

Conclusion: Interactive model is best

mer1 = lmer(var_resid_pct ~ ddm_raw + (1|dv), boot_df %>% filter(rt_acc != "other"))
mer1a = lmer(var_resid_pct ~ overall_difference + (1|dv), boot_df %>% filter(rt_acc != "other"))
mer2 = lmer(var_resid_pct ~ ddm_raw + overall_difference + (1|dv), boot_df %>% filter(rt_acc != "other"))
mer3 = lmer(var_resid_pct ~ ddm_raw * overall_difference + (1|dv), boot_df %>% filter(rt_acc != "other"))
anova(mer1, mer2, mer3)
refitting model(s) with ML (instead of REML)
anova(mer1a, mer2, mer3)
refitting model(s) with ML (instead of REML)
rm(mer1, mer1a, mer2)

Both contrast and condition measures have higher residual variance. Raw and ddm measures do not differ.

summary(mer3)
Linear mixed model fit by REML ['lmerMod']
Formula: var_resid_pct ~ ddm_raw * overall_difference + (1 | dv)
   Data: boot_df %>% filter(rt_acc != "other")

REML criterion at convergence: 3308034

Scaled residuals: 
   Min     1Q Median     3Q    Max 
-6.179 -0.562  0.016  0.604  7.682 

Random effects:
 Groups   Name        Variance Std.Dev.
 dv       (Intercept) 64.7     8.05    
 Residual             37.2     6.10    
Number of obs: 512000, groups:  dv, 512

Fixed effects:
                                       Estimate Std. Error t value
(Intercept)                              19.460      0.868   22.42
ddm_rawraw                                1.279      1.397    0.92
overall_differencecontrast               12.009      1.295    9.27
overall_differencecondition               2.783      1.076    2.59
ddm_rawraw:overall_differencecontrast    -1.387      2.111   -0.66
ddm_rawraw:overall_differencecondition    2.968      1.732    1.71

Correlation of Fixed Effects:
                        (Intr) ddm_rw ovrll_dffrnccnt ovrll_dffrnccnd
ddm_rawraw              -0.621                                       
ovrll_dffrnccnt         -0.670  0.416                                
ovrll_dffrnccnd         -0.806  0.501  0.540                         
ddm_rwrw:vrll_dffrnccnt  0.411 -0.662 -0.614          -0.331         
ddm_rwrw:vrll_dffrnccnd  0.501 -0.807 -0.336          -0.621         
                        ddm_rwrw:vrll_dffrnccnt
ddm_rawraw                                     
ovrll_dffrnccnt                                
ovrll_dffrnccnd                                
ddm_rwrw:vrll_dffrnccnt                        
ddm_rwrw:vrll_dffrnccnd  0.534                 
rm(mer3)

Sample size effects on reliability

Differences in DDM parameter reliability for t1 data using either n=552 or n=150 were reported above under T1 HDDM parameters. No meaningful differences exist between these two sample sizes.

But even 150 is a large sample size for psychological studies, especially forced choice reaction time tasks that are included in this report. Here we look at how the reliability for raw and ddm measures change for sample sizes that are more common in studies using these tasks (25, 50, 75, 100, 125, 150)

Note: Not refitting HDDM’s for each of these sample sizes since a. there were no differences in parameter stability for n=150 vs 552 and b. a more comprehensive comparison using non-hierarchical estimates and model fit indices will follow. [Should I revisit this? - 150 and 552 might be too large to lead to changes in parameter estimates but smaller samples that are more common in psych studies might sway estimates more]

Note: Some variables do not have enough variance to calculate reliability for difference sample sizes. These variables are:
>stroop.post_error_slowing
>simon.std_rt_error
>shape_matching.post_error_slowing
>directed_forgetting.post_error_slowing
>choice_reaction_time.post_error_slowing
>choice_reaction_time.std_rt_error
>dot_pattern_expectancy.post_error_slowing
>motor_selective_stop_signal.go_rt_std_error
>motor_selective_stop_signal.go_rt_error
>attention_network_task.post_error_slowing
>recent_probes.post_error_slowing
>simon.post_error_slowing
>dot_pattern_expectancy.BY_errors

source('/Users/zeynepenkavi/Dropbox/PoldrackLab/SRO_DDM_Analyses/code/workspace_scripts/ddm_reldf_sample_size.R')
Warning: Column `dv` joining factor and character vector, coercing into
character vector

Does the mean reliability change with sample size?

Yes. The larger the sample size the more reliable is a given measure on average. The largest increase in reliability is when shifting from 25 to 50 subjects. This is important because many studies using these measures have sample sizes <50 per group.

fig_name = 'rel_by_samplesize.jpeg'

knitr::include_graphics(paste0(fig_path, fig_name))

When <15 subjects are used to calculate the measures they are significantly less reliable.

summary(lmer(icc ~ sample_size + (1|dv) + (1|iteration), rel_df_sample_size))
Linear mixed model fit by REML ['lmerMod']
Formula: icc ~ sample_size + (1 | dv) + (1 | iteration)
   Data: rel_df_sample_size

REML criterion at convergence: 2823504

Scaled residuals: 
   Min     1Q Median     3Q    Max 
-605.6    0.0    0.0    0.0    0.4 

Random effects:
 Groups    Name        Variance Std.Dev.
 dv        (Intercept)  0.06526 0.2555  
 iteration (Intercept)  0.00427 0.0653  
 Residual              65.64977 8.1025  
Number of obs: 402034, groups:  dv, 505; iteration, 100

Fixed effects:
            Estimate Std. Error t value
(Intercept) 0.311251   0.024771   12.57
sample_size 0.001557   0.000316    4.92

Correlation of Fixed Effects:
            (Intr)
sample_size -0.673

Are there differences between any other sample sizes? This ignores the differences between variables but there seems to be only differences between n=10 and all other larger sample size.

with(rel_df_sample_size_summary, pairwise.t.test(mean_icc, sample_size, p.adjust.method = "bonferroni"))

    Pairwise comparisons using t tests with pooled SD 

data:  mean_icc and sample_size 

    10    15 20 25 50 75 100
15  2e-04 -  -  -  -  -  -  
20  9e-06 1  -  -  -  -  -  
25  2e-06 1  1  -  -  -  -  
50  9e-08 1  1  1  -  -  -  
75  4e-08 1  1  1  1  -  -  
100 3e-08 1  1  1  1  1  -  
125 2e-08 1  1  1  1  1  1  

P value adjustment method: bonferroni 

Does the change in reliabiliity with sample size vary by variable type?

The changes do not differ by raw vs. ddm measures. It does differ by whether the measure is a contrast measure: For contrast measures all increases in reliability with sample size are larger than the increases for non-contrast measures. This implies that larger sample sizes are even more crucial for studies using contrast measures as trait-level measures.

tmp = rel_df_sample_size %>% 
  group_by(sample_size, ddm_raw, overall_difference) %>%
  summarise(mean_icc = mean(icc, na.rm=T),
            sem_icc = sem(icc), 
            mean_var_subs_pct = mean(var_subs_pct, na.rm=T),
            sem_var_subs_pct = sem(var_subs_pct),
            mean_var_ind_pct = mean(var_ind_pct, na.rm=T),
            sem_var_ind_pct = sem(var_ind_pct),
            mean_var_resid_pct = mean(var_resid_pct, na.rm=T),
            sem_var_resid_pct = sem(var_resid_pct)) %>%
  na.exclude()
rel_df_sample_size_summary %>%
  filter(!is.na(overall_difference)) %>%
  ggplot(aes(factor(sample_size), mean_icc))+
  geom_line(aes(group = dv, color=ddm_raw), alpha = 0.1)+
  geom_line(data = tmp, aes(factor(sample_size),mean_icc, color=ddm_raw, group=ddm_raw))+
  geom_point(data = tmp, aes(factor(sample_size),mean_icc, color=ddm_raw))+
  geom_errorbar(data = tmp,aes(ymin=mean_icc-sem_icc, ymax = mean_icc+sem_icc, color=ddm_raw), width = 0.1)+
  facet_wrap(~overall_difference)+
  ylab("Mean reliability of 100 samples of size n")+
  xlab("Sample size")+
  theme(legend.title = element_blank(),
        legend.position = "bottom")+
  ylim(-1,1)
Warning: Removed 122 rows containing missing values (geom_path).

summary(lmer(icc ~ sample_size * overall_difference + (1|dv) + (1|iteration), rel_df_sample_size))
Linear mixed model fit by REML ['lmerMod']
Formula: 
icc ~ sample_size * overall_difference + (1 | dv) + (1 | iteration)
   Data: rel_df_sample_size

REML criterion at convergence: 2805380

Scaled residuals: 
   Min     1Q Median     3Q    Max 
-603.4    0.0    0.0    0.0    0.3 

Random effects:
 Groups    Name        Variance Std.Dev.
 dv        (Intercept)  0.04637 0.2153  
 iteration (Intercept)  0.00433 0.0658  
 Residual              66.14275 8.1328  
Number of obs: 399034, groups:  dv, 499; iteration, 100

Fixed effects:
                                         Estimate Std. Error t value
(Intercept)                              0.518096   0.044356   11.68
sample_size                              0.000621   0.000602    1.03
overall_differencecontrast              -0.459839   0.065919   -6.98
overall_differencecondition             -0.211001   0.054844   -3.85
sample_size:overall_differencecontrast   0.001230   0.000905    1.36
sample_size:overall_differencecondition  0.001343   0.000753    1.78

Correlation of Fixed Effects:
                       (Intr) smpl_s ovrll_dffrnccnt ovrll_dffrnccnd
sample_size            -0.713                                       
ovrll_dffrnccnt        -0.658  0.480                                
ovrll_dffrnccnd        -0.791  0.577  0.532                         
smpl_sz:vrll_dffrnccnt  0.475 -0.665 -0.721          -0.384         
smpl_sz:vrll_dffrnccnd  0.571 -0.800 -0.384          -0.721         
                       smpl_sz:vrll_dffrnccnt
sample_size                                  
ovrll_dffrnccnt                              
ovrll_dffrnccnd                              
smpl_sz:vrll_dffrnccnt                       
smpl_sz:vrll_dffrnccnd  0.532                

Does variability of reliability change with sample size?

No.

rel_df_sample_size_summary %>%
  na.exclude() %>%
  ggplot(aes(sample_size, sem_icc))+
  geom_line(aes(group = dv, color=ddm_raw), alpha = 0.1)+
  geom_line(data = tmp, aes(sample_size,sem_icc, color=ddm_raw))+
  geom_point(data = tmp, aes(sample_size,sem_icc, color=ddm_raw))+
  facet_wrap(~overall_difference)+
  ylab("Standard error of mean of reliability \n of 100 samples of size n")+
  xlab("Sample size")+
  theme(legend.title = element_blank(),
        legend.position = "bottom")

summary(lmer(sem_icc ~ sample_size * overall_difference + (1|dv), rel_df_sample_size_summary))
Linear mixed model fit by REML ['lmerMod']
Formula: sem_icc ~ sample_size * overall_difference + (1 | dv)
   Data: rel_df_sample_size_summary

REML criterion at convergence: 9708

Scaled residuals: 
   Min     1Q Median     3Q    Max 
 -0.12  -0.06  -0.02   0.01  60.38 

Random effects:
 Groups   Name        Variance Std.Dev.
 dv       (Intercept) 0.000213 0.0146  
 Residual             0.657690 0.8110  
Number of obs: 3992, groups:  dv, 499

Fixed effects:
                                         Estimate Std. Error t value
(Intercept)                              0.038630   0.039761    0.97
sample_size                             -0.000334   0.000600   -0.56
overall_differencecontrast               0.048118   0.059791    0.80
overall_differencecondition              0.090710   0.049734    1.82
sample_size:overall_differencecontrast  -0.000466   0.000902   -0.52
sample_size:overall_differencecondition -0.000986   0.000750   -1.31

Correlation of Fixed Effects:
                       (Intr) smpl_s ovrll_dffrnccnt ovrll_dffrnccnd
sample_size            -0.792                                       
ovrll_dffrnccnt        -0.665  0.527                                
ovrll_dffrnccnd        -0.799  0.633  0.532                         
smpl_sz:vrll_dffrnccnt  0.527 -0.665 -0.792          -0.421         
smpl_sz:vrll_dffrnccnd  0.633 -0.799 -0.421          -0.792         
                       smpl_sz:vrll_dffrnccnt
sample_size                                  
ovrll_dffrnccnt                              
ovrll_dffrnccnd                              
smpl_sz:vrll_dffrnccnt                       
smpl_sz:vrll_dffrnccnd  0.532                

Does between subjects variance change with sample size?

Yes. Between subjects variance decreases with sample size. This is more pronounced for non-contrast measures.

This goes against my intuitions. Looking at the change in between subjects percentage of individual measures’ there seems to be a lot of inter-measure variance (more pronounced below for within subject variance). I’m not sure if there is something in common for the measures that show increasing between subjects variability with sample size and that separates them from those that show decreasing between subjects variability with sample size (the slight majority).

rel_df_sample_size_summary %>%
  na.exclude() %>%
  ggplot(aes(sample_size, mean_var_subs_pct))+
  geom_line(aes(group = dv, color=ddm_raw), alpha = 0.1)+
  geom_line(data = tmp, aes(sample_size,mean_var_subs_pct, color=ddm_raw))+
  geom_point(data = tmp, aes(sample_size,mean_var_subs_pct, color=ddm_raw))+
  facet_wrap(~overall_difference)+
  ylab("Mean percentage of \n between subjects variance \n of 100 samples of size n")+
  xlab("Sample size")+
  theme(legend.title = element_blank(),
        legend.position = "bottom")

summary(lmer(var_subs_pct ~ sample_size * overall_difference + (1|dv) + (1|iteration), rel_df_sample_size))
Linear mixed model fit by REML ['lmerMod']
Formula: var_subs_pct ~ sample_size * overall_difference + (1 | dv) +  
    (1 | iteration)
   Data: rel_df_sample_size

REML criterion at convergence: 3274176

Scaled residuals: 
   Min     1Q Median     3Q    Max 
-4.957 -0.705  0.054  0.704  4.556 

Random effects:
 Groups    Name        Variance Std.Dev.
 dv        (Intercept) 109.05   10.44   
 iteration (Intercept)   1.26    1.12   
 Residual              212.51   14.58   
Number of obs: 399034, groups:  dv, 499; iteration, 100

Fixed effects:
                                         Estimate Std. Error t value
(Intercept)                              58.88947    0.89254    66.0
sample_size                              -0.08360    0.00108   -77.5
overall_differencecontrast              -14.86635    1.33152   -11.2
overall_differencecondition              -5.22575    1.10755    -4.7
sample_size:overall_differencecontrast    0.07402    0.00162    45.6
sample_size:overall_differencecondition   0.03666    0.00135    27.2

Correlation of Fixed Effects:
                       (Intr) smpl_s ovrll_dffrnccnt ovrll_dffrnccnd
sample_size            -0.064                                       
ovrll_dffrnccnt        -0.660  0.043                                
ovrll_dffrnccnd        -0.793  0.051  0.532                         
smpl_sz:vrll_dffrnccnt  0.042 -0.665 -0.064          -0.034         
smpl_sz:vrll_dffrnccnd  0.051 -0.800 -0.034          -0.064         
                       smpl_sz:vrll_dffrnccnt
sample_size                                  
ovrll_dffrnccnt                              
ovrll_dffrnccnd                              
smpl_sz:vrll_dffrnccnt                       
smpl_sz:vrll_dffrnccnd  0.532                

Does within subjects variance change with sample size?

Yes. This again goes against my intuition but here the inter-meausre differences are even more pronounced. There appears to be some measures for which the change in two measurements at different time points is larger the more subjects are tested and those that show a smaller decrease in within subject variance with larger sample sizes. I still don’t know if these two types of measures have anything that distinguishes them.

rel_df_sample_size_summary %>%
  na.exclude() %>%
  ggplot(aes(sample_size, mean_var_ind_pct))+
  geom_line(aes(group = dv, color=ddm_raw), alpha = 0.1)+
  geom_line(data = tmp, aes(sample_size,mean_var_ind_pct, color=ddm_raw))+
  geom_point(data = tmp, aes(sample_size,mean_var_ind_pct, color=ddm_raw))+
  facet_wrap(~overall_difference)+
  ylab("Mean percentage of \n within subjects variance \n of 100 samples of size n")+
  xlab("Sample size")+
  theme(legend.title = element_blank(),
        legend.position = "bottom")

summary(lmer(var_ind_pct ~ sample_size * overall_difference + (1|dv) + (1|iteration), rel_df_sample_size))
Linear mixed model fit by REML ['lmerMod']
Formula: var_ind_pct ~ sample_size * overall_difference + (1 | dv) + (1 |  
    iteration)
   Data: rel_df_sample_size

REML criterion at convergence: 3471611

Scaled residuals: 
   Min     1Q Median     3Q    Max 
-4.539 -0.749 -0.171  0.698  4.331 

Random effects:
 Groups    Name        Variance Std.Dev.
 dv        (Intercept) 132.28   11.50   
 iteration (Intercept)   1.41    1.19   
 Residual              348.71   18.67   
Number of obs: 399034, groups:  dv, 499; iteration, 100

Fixed effects:
                                        Estimate Std. Error t value
(Intercept)                             18.28380    0.98355    18.6
sample_size                              0.11368    0.00138    82.2
overall_differencecontrast               5.17440    1.46817     3.5
overall_differencecondition              2.01577    1.22121     1.7
sample_size:overall_differencecontrast  -0.09479    0.00208   -45.6
sample_size:overall_differencecondition -0.03786    0.00173   -21.9

Correlation of Fixed Effects:
                       (Intr) smpl_s ovrll_dffrnccnt ovrll_dffrnccnd
sample_size            -0.074                                       
ovrll_dffrnccnt        -0.660  0.050                                
ovrll_dffrnccnd        -0.794  0.060  0.532                         
smpl_sz:vrll_dffrnccnt  0.049 -0.665 -0.074          -0.040         
smpl_sz:vrll_dffrnccnd  0.059 -0.800 -0.040          -0.074         
                       smpl_sz:vrll_dffrnccnt
sample_size                                  
ovrll_dffrnccnt                              
ovrll_dffrnccnd                              
smpl_sz:vrll_dffrnccnt                       
smpl_sz:vrll_dffrnccnd  0.532                

Does residual variance change with sample size?

rel_df_sample_size_summary %>%
  na.exclude() %>%
  ggplot(aes(sample_size, mean_var_resid_pct))+
  geom_line(aes(group = dv, color=ddm_raw), alpha = 0.1)+
  geom_line(data = tmp, aes(sample_size,mean_var_resid_pct, color=ddm_raw))+
  geom_point(data = tmp, aes(sample_size,mean_var_resid_pct, color=ddm_raw))+
  facet_wrap(~overall_difference)+
  ylab("Mean percentage of residual variance \n of 100 samples of size n")+
  xlab("Sample size")+
  theme(legend.title = element_blank(),
        legend.position = "bottom")

summary(lmer(var_resid_pct ~ sample_size * overall_difference + (1|dv) + (1|iteration), rel_df_sample_size))
Linear mixed model fit by REML ['lmerMod']
Formula: var_resid_pct ~ sample_size * overall_difference + (1 | dv) +  
    (1 | iteration)
   Data: rel_df_sample_size

REML criterion at convergence: 2942570

Scaled residuals: 
   Min     1Q Median     3Q    Max 
-4.562 -0.624 -0.040  0.559  8.279 

Random effects:
 Groups    Name        Variance Std.Dev.
 dv        (Intercept) 39.93    6.319   
 iteration (Intercept)  0.44    0.663   
 Residual              92.59    9.623   
Number of obs: 399034, groups:  dv, 499; iteration, 100

Fixed effects:
                                         Estimate Std. Error t value
(Intercept)                             22.826752   0.540234    42.3
sample_size                             -0.030083   0.000712   -42.2
overall_differencecontrast               9.691933   0.806229    12.0
overall_differencecondition              3.209963   0.670616     4.8
sample_size:overall_differencecontrast   0.020769   0.001071    19.4
sample_size:overall_differencecondition  0.001197   0.000891     1.3

Correlation of Fixed Effects:
                       (Intr) smpl_s ovrll_dffrnccnt ovrll_dffrnccnd
sample_size            -0.069                                       
ovrll_dffrnccnt        -0.660  0.046                                
ovrll_dffrnccnd        -0.793  0.056  0.532                         
smpl_sz:vrll_dffrnccnt  0.046 -0.665 -0.070          -0.037         
smpl_sz:vrll_dffrnccnd  0.055 -0.800 -0.037          -0.070         
                       smpl_sz:vrll_dffrnccnt
sample_size                                  
ovrll_dffrnccnt                              
ovrll_dffrnccnd                              
smpl_sz:vrll_dffrnccnt                       
smpl_sz:vrll_dffrnccnd  0.532                

Conclusion: Larger samples are better for reliability but not necessarily always for the same reasons; for some variables this is due to increasing between subjects variance while for others it’s due to decreasing residual variance (?).

rm(rel_df_sample_size, rel_df_sample_size_summary)

Hierarchical estimation consequences

The H in HDDM estimates stands for ‘hierarchical’ denoting the fact that the distribution of the whole sample is incorportated in the priors for the model parameters. This is different than e.g. EZ-diffusion parameters that would be the same for a given subject’s data regardless of the rest of the sample. One can ask whether this H indeed has a measurable impact.

HDDM and EZ parameter estimates might differ due to other difference in the estimation process as well. Therefore to evaluate whether the ‘H’ leads to meaningful changes in parameters we compare the same models fit on the same data using either the whole sample for the hierarchical structure or only the single subject’s data. These latter estimates are referred to as ‘flat’ estimates.

retest_hddm_flat = read.csv(paste0(retest_data_path,'retest_hddm_flat.csv'))

retest_hddm_flat = retest_hddm_flat %>% rename(sub_id = subj_id)

test_hddm_flat = read.csv(paste0(retest_data_path,'/t1_data/t1_hddm_flat.csv'))

test_hddm_flat = test_hddm_flat %>% rename(sub_id = subj_id)

# numeric_cols = get_numeric_cols()

# Check if all the variables are there (no for now)
# sum(names(retest_hddm_flat) %in% numeric_cols) == length(names(retest_hddm_flat))
# names(retest_hddm_flat)[which(names(retest_hddm_flat) %in% numeric_cols == FALSE)]

# sum(names(test_hddm_flat) %in% numeric_cols) == length(names(test_hddm_flat))
# names(test_hddm_flat)[which(names(test_hddm_flat) %in% numeric_cols == FALSE)]

Parameter estimate

Plot percent change in raw parameters for retest and t1 for each of 3 parameters (using hierarchical as baseline: what percent does the flat parameter change compared to the hierarchical)

For both time points the thresholds and non-decision times are very similary regardless of whether they are estimated heirarchically or without the hierarchy (difference peaking at 0).

This is also true for the majority of the drift rates. There are, however, almost as many drift rates that change completely when estimated without the hierarchy.

#Should not be necessary later
common_cols = names(retest_hddm_flat)[names(retest_hddm_flat) %in% names(retest_data)]
common_cols=common_cols[common_cols %in% names(test_hddm_flat)]

retest_hddm_hier = retest_data %>% select(common_cols) %>% mutate(hddm="hierarchical")
test_hddm_hier = test_data %>% select(common_cols)  %>% mutate(hddm="hierarchical")
retest_hddm_flat = retest_hddm_flat %>% select(common_cols) %>% mutate(hddm="flat")
test_hddm_flat = test_hddm_flat %>% select(common_cols) %>% mutate(hddm="flat")

retest_flat_difference = rbind(retest_hddm_hier, retest_hddm_flat)
retest_flat_difference = retest_flat_difference %>%
  gather(dv, value, -sub_id, -hddm) %>%
  spread(hddm, value) %>%
  mutate(diff_pct = (hierarchical - flat)/hierarchical*100,
         diff_pct = ifelse(diff_pct<(-100), -100, ifelse(diff_pct>100, 100, diff_pct)),
         time = "retest",
         par = ifelse(grepl("drift", dv), "drift", ifelse(grepl("thresh", dv), "thresh", ifelse(grepl("non_decision", dv), "non_decision", NA))))

test_flat_difference = rbind(test_hddm_hier, test_hddm_flat)
test_flat_difference = test_flat_difference %>%
  gather(dv, value, -sub_id, -hddm) %>%
  spread(hddm, value) %>%
  mutate(diff_pct = (hierarchical - flat)/hierarchical*100,
         diff_pct = ifelse(diff_pct<(-100), -100, ifelse(diff_pct>100, 100, diff_pct)),
         time = "test",
         par = ifelse(grepl("drift", dv), "drift", ifelse(grepl("thresh", dv), "thresh", ifelse(grepl("non_decision", dv), "non_decision", NA))))

flat_difference = rbind(test_flat_difference, retest_flat_difference)

flat_difference %>%
  ggplot(aes(diff_pct))+
  geom_histogram()+
  facet_grid(factor(time, levels = c("test", "retest"),labels = c("test", "retest")) ~ par, scales="free")
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
Warning: Removed 1022 rows containing non-finite values (stat_bin).

Is the average percentage change different than 0? No.

This model uses the distribution of percentage difference in parameter estimates for drift rates as the baseline. A more appropriate model would test whether all three distributions are different than 0. The conclusion should not change: The intercept suggests that the mean of the drift rate difference distribution is at 0 and this is not different than the distributions for either of the other parameters and either time point.

summary(lmer(diff_pct ~ time*par+(1|dv), flat_difference %>% mutate(pars = factor(par, levels = c("thresh", "drift", "non_decision")))))
Linear mixed model fit by REML ['lmerMod']
Formula: diff_pct ~ time * par + (1 | dv)
   Data: 
flat_difference %>% mutate(pars = factor(par, levels = c("thresh",  
    "drift", "non_decision")))

REML criterion at convergence: 238677

Scaled residuals: 
   Min     1Q Median     3Q    Max 
-3.244 -0.258 -0.016  0.213  3.853 

Random effects:
 Groups   Name        Variance Std.Dev.
 dv       (Intercept)  130     11.4    
 Residual             1443     38.0    
Number of obs: 23578, groups:  dv, 82

Fixed effects:
                         Estimate Std. Error t value
(Intercept)                 -1.19       1.64   -0.73
timetest                     1.64       0.62    2.65
parnon_decision              1.65       3.57    0.46
parthresh                   -1.84       3.39   -0.54
timetest:parnon_decision    -1.38       1.35   -1.02
timetest:parthresh          -1.71       1.28   -1.33

Correlation of Fixed Effects:
            (Intr) timtst prnn_d prthrs tmts:_
timetest    -0.191                            
parnon_dcsn -0.460  0.088                     
parthresh   -0.485  0.093  0.223              
tmtst:prnn_  0.088 -0.459 -0.191 -0.043       
tmtst:prthr  0.092 -0.483 -0.042 -0.192  0.222

Do people change in the same way? Mostly.

Plotting the raw parameter estimate that is estimated hierarchically against the estimate that is estimated without the hierarchy. Red lines are the 45-degree line. The fact that many points cluster around this line and that there are systematic deviances from it for any parameter at either time point suggests that the hierarchical and flat estimates are mostly the same.

flat_difference %>%
  ggplot(aes(hierarchical, flat))+
  geom_point()+
  geom_abline(aes(intercept=0, slope=1), color="red")+
  facet_grid(factor(time, levels = c("test", "retest"),labels = c("test", "retest")) ~ par)
Warning: Removed 1022 rows containing missing values (geom_point).

Parameter reliability

Plotting the reliability estimates for flat parameters against the reliability of hierarchical estimates. Red lines are 45-degree lines. While there are some changes in reliability nothing appears very large (or consequential in pushing the reliability to any acceptable level depending on the estimation method) or systematic.

rel_df_flat = make_rel_df(t1_df = test_hddm_flat, t2_df = retest_hddm_flat, metrics = c('icc', 'pearson', 'var_breakdown'))

rel_df_flat = rel_df_flat %>%
  left_join(rel_df[,c("dv", "icc", "rt_acc", "overall_difference")], by = "dv") 

rel_df_flat %>%
  ggplot(aes(icc.y, icc.x))+
  geom_point()+
  geom_abline(aes(slope=1, intercept = 0), color="red")+
  facet_wrap(~rt_acc)+
  xlab("Hierarchical reliability")+
  ylab("Flat reliability")

with(rel_df_flat %>% filter(rt_acc == "drift rate"), t.test(icc.x, icc.y, paired=T))

    Paired t-test

data:  icc.x and icc.y
t = 0.53, df = 51, p-value = 0.6
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
 -0.02018  0.03454
sample estimates:
mean of the differences 
               0.007181 
with(rel_df_flat %>% filter(rt_acc == "threshold"), t.test(icc.x, icc.y, paired=T))

    Paired t-test

data:  icc.x and icc.y
t = -2, df = 15, p-value = 0.06
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
 -0.088179  0.002222
sample estimates:
mean of the differences 
               -0.04298 
with(rel_df_flat %>% filter(rt_acc == "non-decision"), t.test(icc.x, icc.y, paired=T))

    Paired t-test

data:  icc.x and icc.y
t = -0.19, df = 13, p-value = 0.9
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
 -0.04691  0.03948
sample estimates:
mean of the differences 
              -0.003715 
rm(flat_difference, rel_df_flat, retest_flat_difference, retest_hddm_flat, retest_hddm_hier, test_flat_difference,  test_hddm_flat, test_hddm_hier)

Parameter fit

Do the fit statistics differ by whether the model was hierarchical or not? No.

t1_hierarchical_fitstats = t1_hierarchical_fitstats %>%
  filter(subj_id %in% retest_hierarchical_fitstats$subj_id)

tmp = rbind(retest_hierarchical_fitstats, retest_flat_fitstats, t1_hierarchical_fitstats, t1_flat_fitstats) %>%
  separate(sample, c("time", "proc"), sep="_") %>%
  select(log_rsq_adj, time, proc, subj_id, task_name) %>%
  spread(proc, log_rsq_adj) 

tmp %>%
  ggplot(aes(hierarchical, flat))+
  geom_point()+
  geom_abline(aes(slope=1, intercept=0), color="red")+
  facet_wrap(~time)
Warning: Removed 271 rows containing missing values (geom_point).

with(tmp %>% filter(time == "t1"), cor.test(flat, hierarchical))

    Pearson's product-moment correlation

data:  flat and hierarchical
t = 59, df = 1900, p-value <2e-16
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
 0.7855 0.8174
sample estimates:
   cor 
0.8021 
with(tmp %>% filter(time == "retest"), cor.test(flat, hierarchical))

    Pearson's product-moment correlation

data:  flat and hierarchical
t = 62, df = 2000, p-value <2e-16
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
 0.7942 0.8244
sample estimates:
   cor 
0.8098 
with(tmp %>% filter(time == "t1"), t.test(flat, hierarchical, paired=TRUE))

    Paired t-test

data:  flat and hierarchical
t = 0.16, df = 1900, p-value = 0.9
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
 -0.0007680  0.0009064
sample estimates:
mean of the differences 
             0.00006916 
with(tmp %>% filter(time == "retest"), t.test(flat, hierarchical, paired=TRUE))

    Paired t-test

data:  flat and hierarchical
t = 1.2, df = 2000, p-value = 0.2
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
 -0.0002551  0.0010165
sample estimates:
mean of the differences 
              0.0003807 

Clustering

– Do DDM parameters capture similar processes as the raw measures in a given task or do they capture processes that are more similar across tasks? (If the former they would be less useful than if the latter.)

This could be analyzed with factor analysis but there are more variables than observations so as a first pass we’ll explore correlations.

For this we correlate each DDM measure with:
1. raw measures within task
2. other ddm measures across tasks

(Absolute) correlations between raw and ddm measures within a task are higher than those between ddm measures across tasks.

Factor analysis

– Are these clusters more reliable than using either the raw or the DDM measures alone?

Prediction

– Do raw or DDM measures (or factor scores) predict real world outcomes better?

To Do

  • Alternate DDMs
  • Time and accuracy costs vs DDMs (Hedge et al, 2018, Psych Bull)
  • Trial by trial variability as individual difference measres (Rouder and Haaf, psyArXiv)
LS0tCnRpdGxlOiAnU2VsZiBSZWd1bGF0aW9uIE9udG9sb2d5IERETSBBbmFseXNlcycKb3V0cHV0OgpnaXRodWJfZG9jdW1lbnQ6CnRvYzogeWVzCnRvY19mbG9hdDogeWVzCi0tLQoKYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGluY2x1ZGU9RkFMU0V9CnNvdXJjZSgnL1VzZXJzL3pleW5lcGVua2F2aS9Ecm9wYm94L1BvbGRyYWNrTGFiL1NST19ERE1fQW5hbHlzZXMvY29kZS93b3Jrc3BhY2Vfc2NyaXB0cy9TUk9fRERNX0FuYWx5c2VzX1dvcmtzcGFjZS5SJykKYGBgCgpUaGUgdGFza3MgaW5jbHVkZWQgaW4gdGhpcyByZXBvcnQgYXJlOiAgCgpgYGB7cn0KdW5pcXVlKG1lYXN1cmVfbGFiZWxzJHRhc2tfZ3JvdXApCmBgYAoKIyMgVDEgSERETSBwYXJhbWV0ZXJzCgpCZWZvcmUgZ29pbmcgb24gd2l0aCB0aGUgcmVzdCBvZiB0aGUgcmVwb3J0IGZpcnN0IGRlY2lkZSBvbiB3aGV0aGVyIHRoZXJlIGFyZSBzaWduaWZpY2FudCBkaWZmZXJlbmNlcyBpbiB0aGUgZGlzdHJpYnV0aW9ucyBvZiB0aGUgSERETSBwYXJhbWV0ZXIgZXN0aW1hdGVzIGFuZCB0aGVpciByZWxpYWJpbGl0aWVzIGRlcGVuZGluZyBvbiB3aGV0aGVyIHRoZXkgYXJlIGZpdCBvbiB0aGUgZnVsbCBzYW1wbGUgKG49NTUyKSBvciByZXRlc3Qgc2FtcGxlIChuPTE1MCkgZm9yIHQxIGRhdGEuICAKCiMjIyBQYXJhbWV0ZXIgc3RhYmlsaXR5CgpEaWZmZXJlbmNlcyBpbiBkaXN0cmlidXRpb25zOiB1c2luZyBzY2FsZWQgZGlmZmVyZW5jZXMKCmBgYHtyIGVjaG89RkFMU0UsIG91dC53aWR0aD0nMTAwJSd9CmZpZ19uYW1lID0gJ0hERE1fcGFyX2RpZmYuanBlZycKCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKHBhc3RlMChmaWdfcGF0aCwgZmlnX25hbWUpKQpgYGAKCkRvZXMgdGhlIGRpc3RyaWJ1dGlvbiBvZiBzY2FsZWQgZGlmZmVyZW5jZSBzY29yZXMgKGJldHdlZW4gdXNpbmcgbj0xNTAgb3Igbj01NTIpIGhhdmUgYSBtZWFuIGRpZmZlcmVudCB0aGFuIDAgYWxsb3dpbmcgZm9yIHJhbmRvbSBlZmZlY3RzIG9mIHBhcmFtZXRlciBhY2NvdW50aW5nIGZvciB0aGUgZGlmZmVyZW50IHR5cGVzIG9mIHBhcmFtZXRlcnM/IE5vLgoKYGBge3J9CmlmKCFleGlzdHMoJ2hkZG1fcGFycycpKXsKICBzb3VyY2UoJy9Vc2Vycy96ZXluZXBlbmthdmkvRHJvcGJveC9Qb2xkcmFja0xhYi9TUk9fRERNX0FuYWx5c2VzL2NvZGUvd29ya3NwYWNlX3NjcmlwdHMvaGRkbV9wYXJzX2RhdGEuUicpCn0Kc3VtbWFyeShsbWVyKHNjYWxlZF9kaWZmIH4gcnRfYWNjICsgKDF8ZHYpLCBoZGRtX3BhcnMpKQojIFNhbWUgcmVzdWx0CiMgc3VtbWFyeShNQ01DZ2xtbShzY2FsZWRfZGlmZiB+IHJ0X2FjYywgcmFuZG9tID0gfiBkdiwgZGF0YT1oZGRtX3BhcnMpKQpgYGAKCiMjIyBQYXJhbWV0ZXIgcmVsaWFiaWxpdHkKCkFyZSB0aGVyZSBkaWZmZXJlbmNlcyBpbiByZWxpYWJpbGl0eSBkZXBlbmRpbmcgd2hpY2ggc2FtcGxlIHRoZSBIRERNIHBhcmFtZXRlcnMgYXJlIGVzdGltYXRlZCBmcm9tPyBOby4KCmBgYHtyIGVjaG89RkFMU0UsIG91dC53aWR0aD0nMTAwJSd9CmZpZ19uYW1lID0gJ0hERE1fcmVsXzE1MHZzNTUyLmpwZWcnCgprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhwYXN0ZTAoZmlnX3BhdGgsIGZpZ19uYW1lKSkKYGBgCgpEbyBoZGRtIHBhcmFtZXRlcnMgZGlmZmVyIGluIHRoZWlyIHJlbGlhYmlsaXR5IGRlcGVuZGluZyBvbiB3aGV0aGVyIHRoZXkgYXJlIGRlcml2ZWQgZnJvbSBuPTE1MCBvciBuPTU1Mj8gTm8uCgpgYGB7cn0KaWYoIWV4aXN0cygnaGRkbV9yZWxzJykpewogIHNvdXJjZSgnL1VzZXJzL3pleW5lcGVua2F2aS9Ecm9wYm94L1BvbGRyYWNrTGFiL1NST19ERE1fQW5hbHlzZXMvY29kZS93b3Jrc3BhY2Vfc2NyaXB0cy9oZGRtX3JlbF9kYXRhLlInKX0KCmhkZG1fcmVscyA9IGhkZG1fcmVscyAlPiUKICBnYXRoZXIoc2FtcGxlLCB2YWx1ZSwgLWR2LCAtcnRfYWNjKQoKc3VtbWFyeShsbWVyKHZhbHVlIH4gc2FtcGxlKnJ0X2FjYyArICgxfGR2KSwgaGRkbV9yZWxzKSkKYGBgCgojIyMgUGFyYW1ldGVyIGZpdAoKRG8gSERETSBwYXJhbWV0ZXIgZXN0aW1hdGVzIGZpdCBwYXJ0aWNpcGFudCBkYXRhIGJldHRlciBpZiB0aGUgbW9kZWwgcHJpb3IgaXMgaW5mb3JtZWQgYnkgYSBsYXJnZXIgc2FtcGxlPyBUbyBhc3Nlc3MgbW9kZWwgZml0IHdlIHNhbXBsZWQgZnJvbSB0aGUgcG9zdGVyaW9yIHByZWRpY3RpdmUgZm9yIGVhY2ggc3ViamVjdCBhbmQgcmVncmVzc2VkIHRoZSBwcmVkaWN0ZWQgUlQncyBvbiBhY3R1YWwgUlQncyAodXNpbmcgYm90aCByYXcgUlQncyBhcyB3ZWxsIGFzIGxvZy10cmFuc2Zvcm1lZCBSVCdzKS4gT3VyIG1lYXN1cmUgb2YgZml0IGlzIHRoZSAoYWRqdXN0ZWQpICRSXjIkIGZyb20gdGhlc2UgcmVncmVzc2lvbnMgZm9yIGVhY2ggcGFydGljaXBhbnQuCgpIZXJlIHdlIGNvbXBhcmUgbW9kZWwgZml0cyBiZXR3ZWVuIHRoZSBzYW1lIG1vZGVsIHVzaW5nIGEgcHJpb3IgdXNpbmcgbj01NTIgdnMgbj0xNTAuCgoqTm90ZToqIEluIGNhbGN1bGF0aW5nIHRoZSBmaXQgc3RhdGlzdGljcyBmb3IgdGhlIGZ1bGwgc2FtcGxlIChuPTU1MikgaGllcmFyY2hpY2FsIG1vZGVscyB3ZSB1c2VkIGZld2VyIHNhbXBsZXMgZnJvbSB0aGUgcG9zdGVyaW9yIHByZWRpY3RpdmUgZHVlIHRvIGNvbXB1dGF0aW9uYWwgY29uc3RyYWludHMuIFdlIGRpZCwgaG93ZXZlciwgY29uZmlybSB0aGF0IHRoZSBudW1iZXIgb2Ygc2FtcGxlcyBmcm9tIHRoZSBwb3N0ZXJpb3IgcHJlZGljdGl2ZSBkaWQgbm90IGhhdmUgYW4gZWZmZWN0IG9uIHRoZSBmaXQgc3RhdGlzdGljcy4gRGV0YWlscyBvZiB0aG9zZSBhbmFseXNlcyBjYW4gYmUgZm91bmQgW2hlcmVdKGh0dHBzOi8vemVua2F2aS5naXRodWIuaW8vU1JPX0RETV9BbmFseXNlcy9vdXRwdXQvcmVwb3J0cy9OdW1TYW1wbGVzQW5hbHlzaXMubmIuaHRtbCkuCgpgYGB7ciBtZXNzYWdlPUZBTFNFfQpyZWZpdF9maXRzdGF0cyAlPiUKICBsZWZ0X2pvaW4odDFfaGllcmFyY2hpY2FsX2ZpdHN0YXRzLCBieSA9IGMoInN1YmpfaWQiLCAidGFza19uYW1lIikpICU+JQogIGdncGxvdChhZXMobG9nX3JzcV9hZGoueCwgbG9nX3JzcV9hZGoueSkpKwogIGdlb21fcG9pbnQoYWVzKGNvbG9yPXRhc2tfbmFtZSkpKwogIHhsYWIoIkFkanVzdGVkIHItc3EgZm9yIG49MTUwIikrCiAgeWxhYigiQWRqdXN0ZWQgci1zcSBmb3Igbj01NTIiKSsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpKwogIGdlb21fYWJsaW5lKHNsb3BlID0gMSwgaW50ZXJjZXB0PTApCmBgYAoKVGhlIGZpdCBzdGF0aXN0aWNzIChsb29raW5nIGhlcmUgYXQgdGhlIGFkanVzdGVkICRSXjIkcyB1c2luZyBsb2ctdHJhbnNmb3JtZWQgUlQncykgZm9yIHRoZSBzYW1lIG1vZGVscyB1c2luZyBuPTU1MiBhbmQgbj0xNTAgZm9yIHRoZSBwcmlvcnMgYXJlIGhpZ2hseSBjb3JyZWxhdGVkLgoKYGBge3J9CnRtcCA9IHJlZml0X2ZpdHN0YXRzICU+JQogIGxlZnRfam9pbih0MV9oaWVyYXJjaGljYWxfZml0c3RhdHMsIGJ5ID0gYygic3Vial9pZCIsICJ0YXNrX25hbWUiKSkKCndpdGgodG1wLCBjb3IudGVzdChsb2dfcnNxX2Fkai54LCBsb2dfcnNxX2Fkai55KSkKYGBgCgpBbmQgdGhleSBkbyBub3Qgc3lzdGVtYXRpY2FsbHkgZGlmZmVyIGZyb20gZWFjaCBvdGhlci4KCmBgYHtyfQp3aXRoKHRtcCwgdC50ZXN0KGxvZ19yc3FfYWRqLngsIGxvZ19yc3FfYWRqLnksIHBhaXJlZD1UKSkKYGBgCgoqQ29uY2x1c2lvbjoqIFBhcmFtZXRlciBlc3RpbWF0ZXMgZnJvbSByZWZpdHMgdG8gcmV0ZXN0IHNhbXBsZSBvbmx5IGZvciB0MSBkYXRhIGRvIG5vdCBkaWZmZXIgaW4gYW55IGRldGVjdGFibGUgd2F5IGZyb20gZXN0aW1hdGVzIHVzaW5nIHRoZSBmdWxsIHQxIHNhbXBsZS4gVGhleSBhcmUgYWxzbyBpbiBwcmluY2lwbGUgbW9yZSBjb21wYXJhYmxlIHRvIHRoZSBwYXJhbWV0ZXIgZXN0aW1hdGVzIGZyb20gdDIgYW5kIHRoZXJlZm9yZSB1c2VkIGluIHRoZSByZXN0IG9mIHRoaXMgcmVwb3J0LgoKCmBgYHtyIGVjaG89RkFMU0V9CiNXb3Jrc3BhY2UgY2xlYW4gdXAKcm0odG1wKQoKcm0oaGRkbV9wYXJzLCBoZGRtX3JlbHMpCgpib290X2RmID0gZnVsbGZpdF9ib290X2RmICU+JQogIGZpbHRlcihkdiAlaW4lIHVuaXF1ZShyZWZpdF9ib290X2RmJGR2KSA9PSBGQUxTRSkKCmJvb3RfZGYgPSByYmluZChib290X2RmLCByZWZpdF9ib290X2RmKQoKcm0oZnVsbGZpdF9ib290X2RmLCByZWZpdF9ib290X2RmKQoKcmVsX2RmID0gcmVsX2RmX3JlZml0CgpybShyZWxfZGZfZnVsbGZpdCwgcmVsX2RmX3JlZml0KQoKdGVzdF9kYXRhID0gdGVzdF9kYXRhX2hkZG1fcmVmaXQKCnJtKHRlc3RfZGF0YV9oZGRtX2Z1bGxmaXQsIHRlc3RfZGF0YV9oZGRtX3JlZml0KQpgYGAKCiMjIERETSB2cyByYXcgcmVsaWFiaWxpdHkgb3ZlcmFsbAoKUGxvdCByZWxpYWJpbGl0eSBwb2ludCBlc3RpbWF0ZXMgY29tcGFyaW5nIERETSBtZWFzdXJlcyB0byByYXcgbWVhc3VyZXMgZmFjZXRpbmcgZm9yIGNvbnRyYXN0IG1lYXN1cmVzLgoKYGBge3J9CmZpZ19uYW1lID0gJ2RkbXZzcmF3X3BvaW50LmpwZWcnCgprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhwYXN0ZTAoZmlnX3BhdGgsIGZpZ19uYW1lKSkKYGBgCgpQbG90IGF2ZXJhZ2VkIGJvb3RzdHJhcHBlZCByZWxpYWJpbGl0eSBlc3RpbWF0ZXMgcGVyIG1lYXN1cmUgY29tcGFyaW5nIERETSBtZWFzdXJlcyB0byByYXcgbWVhc3VyZXMgZmFjZXRpbmcgZm9yIGNvbnRyYXN0IG1lYXN1cmVzLgoKYGBge3J9CmZpZ19uYW1lID0gJ2RkbXZzcmF3X2Jvb3QuanBlZycKCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKHBhc3RlMChmaWdfcGF0aCwgZmlnX25hbWUpKQpgYGAKCk1vZGVsIHRlc3RpbmcgaWYgdGhlIHJlbGlhYmlsaXR5IG9mIHJhdyBtZWFzdXJlcyBkaWZmZXJzIGZyb20gdGhhdCBvZiBkZG0gZXN0aW1hdGVzIGFuZCBpZiBjb250cmFzdCBtZWFzdXJlcyBkaWZmZXIgZnJvbSBub24tY29udHJhc3QgbWVhc3VyZXMuCgpDaGVja2luZyBpZiBib3RoIGZpeGVkIGVmZmVjdHMgb2YgcmF3IHZzIGRkbSBhbmQgY29udHJhc3QgdnMgbm9uLWNvbnRyYXN0IGFzIHdlbGwgYXMgdGhlaXIgaW50ZXJhY3Rpb24gaXMgbmVjZXNzYXJ5LgoKQ29uY2x1c2lvbjogSW50ZXJhY3RpdmUgbW9kZWwgaXMgYmVzdC4KCmBgYHtyfQptZXIxID0gbG1lcihpY2MgfiBkZG1fcmF3ICsgKDF8ZHYpLCBib290X2RmICU+JSBmaWx0ZXIocnRfYWNjICE9ICJvdGhlciIpKQptZXIxYSA9IGxtZXIoaWNjIH4gb3ZlcmFsbF9kaWZmZXJlbmNlICsgKDF8ZHYpLCBib290X2RmICU+JSBmaWx0ZXIocnRfYWNjICE9ICJvdGhlciIpKQptZXIyID0gbG1lcihpY2MgfiBkZG1fcmF3ICsgb3ZlcmFsbF9kaWZmZXJlbmNlICsgKDF8ZHYpLCBib290X2RmICU+JSBmaWx0ZXIocnRfYWNjICE9ICJvdGhlciIpKQptZXIzID0gbG1lcihpY2MgfiBkZG1fcmF3ICogb3ZlcmFsbF9kaWZmZXJlbmNlICsgKDF8ZHYpLCBib290X2RmICU+JSBmaWx0ZXIocnRfYWNjICE9ICJvdGhlciIpKQphbm92YShtZXIxLCBtZXIyLCBtZXIzKQphbm92YShtZXIxYSwgbWVyMiwgbWVyMykKYGBgCgpgYGB7cn0Kcm0obWVyMSwgbWVyMiwgbWVyMWEpCmBgYAoKUmF3IG1lYXN1cmVzIGRvIG5vdCBzaWduaWZpY2FudGx5IGRpZmZlciBmcm9tIGRkbSBwYXJhbWV0ZXJzIGluIHRoZWlyIHJlbGlhYmlsaXR5IGJ1dCBub24tY29udHJhc3QgbWVhc3VyZXMgYXJlIHNpZ25pZmljYW50bHkgbW9yZSByZWxpYWJsZSBjb21wYXJlZCB0byBjb250cmFzdCBhbmQgY29uZGl0aW9uIG1lYXN1cmVzLgoKYGBge3J9CnN1bW1hcnkobWVyMykKYGBgCgojIyMgQmVzdCBtZWFzdXJlIGZvciBlYWNoIHRhc2sKCldoYXQgaXMgdGhlIGJlc3QgbWVhc3VyZSBvZiBpbmRpdmlkdWFsIGRpZmZlcmVuY2UgZm9yIGFueSBtZWFzdXJlIHRoYXQgaGFzIGJvdGggcmF3IGFuZCBERE0gcGFyYW1ldGVycz8gCgpFdmVuIHRob3VnaCBvdmVyYWxsIHRoZSBkZG0gcGFyYW1ldGVycyBhcmUgbm90IHNpZ25pZmljYW50bHkgbGVzcyByZWxpYWJsZSB0aGUgbW9zdCByZWxpYWJsZSBtZWFzdXJlIGlzIG1vcmUgZnJlcXVlbnRseSBhIHJhdyBtZWFzdXJlLiBUaGVyZSBhcmUgc29tZSBleGFtcGxlcyBvZiBhbiBFWiBlc3RpbWF0ZSBiZWluZyB0aGUgYmVzdCBmb3IgYSB0YXNrIGFzIHdlbGwuIFJlZ2FyZGxlc3Mgb2YgcmF3IHZzIGRkbSB0aGUgYmVzdCBtZWFzdXJlIGlzIGFsd2F5cyBhIG5vbi1jb250cmFzdCBtZWFzdXJlLiAKCmBgYHtyfQpyZWxfZGYgJT4lCiAgZ3JvdXBfYnkodGFza19ncm91cCkgJT4lCiAgZmlsdGVyKGljYyA9PSBtYXgoaWNjKSkgJT4lCiAgc2VsZWN0KHRhc2tfZ3JvdXAsIGV2ZXJ5dGhpbmcoKSkKYGBgCgojIyMgVmFyaWFuY2UgYnJlYWtkb3duIG1lYXN1cmUgdHlwZXMKCmBgYHtyfQpmaWdfbmFtZSA9ICdkZG12c3Jhd192YXJzdWJzLmpwZWcnCgprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhwYXN0ZTAoZmlnX3BhdGgsIGZpZ19uYW1lKSkKYGBgCgpgYGB7cn0KZmlnX25hbWUgPSAnZGRtdnNyYXdfdmFycmVzaWQuanBlZycKCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKHBhc3RlMChmaWdfcGF0aCwgZmlnX25hbWUpKQpgYGAKCk1vZGVsIHRlc3RpbmcgaWYgdGhlIHBlcmNlbnRhZ2Ugb2YgYmV0d2VlbiBzdWJqZWN0cyB2YXJpYW5jZSBvZiByYXcgbWVhc3VyZXMgZGlmZmVycyBmcm9tIHRoYXQgb2YgZGRtIGVzdGltYXRlcyBhbmQgaWYgY29udHJhc3QgbWVhc3VyZXMgZGlmZmVyIGZyb20gbm9uLWNvbnRyYXN0IG1lYXN1cmVzLgoKQ2hlY2tpbmcgaWYgYm90aCBmaXhlZCBlZmZlY3RzIG9mIHJhdyB2cyBkZG0gYW5kIGNvbnRyYXN0IHZzIG5vbi1jb250cmFzdCBhcyB3ZWxsIGFzIHRoZWlyIGludGVyYWN0aW9uIGlzIG5lY2Vzc2FyeS4KCkNvbmNsdXNpb246IE1vZGVsIHdpdGggZml4ZWQgZWZmZWN0cyBmb3IgYm90aCBpcyBiZXN0LgoKYGBge3J9Cm1lcjEgPSBsbWVyKHZhcl9zdWJzX3BjdCB+IGRkbV9yYXcgKyAoMXxkdiksIGJvb3RfZGYgJT4lIGZpbHRlcihydF9hY2MgIT0gIm90aGVyIikpCm1lcjFhID0gbG1lcih2YXJfc3Vic19wY3QgfiBvdmVyYWxsX2RpZmZlcmVuY2UgKyAoMXxkdiksIGJvb3RfZGYgJT4lIGZpbHRlcihydF9hY2MgIT0gIm90aGVyIikpCm1lcjIgPSBsbWVyKHZhcl9zdWJzX3BjdCB+IGRkbV9yYXcgKyAgb3ZlcmFsbF9kaWZmZXJlbmNlICsgKDF8ZHYpLCBib290X2RmICU+JSBmaWx0ZXIocnRfYWNjICE9ICJvdGhlciIpKQptZXIzID0gbG1lcih2YXJfc3Vic19wY3QgfiBkZG1fcmF3ICogIG92ZXJhbGxfZGlmZmVyZW5jZSArICgxfGR2KSwgYm9vdF9kZiAlPiUgZmlsdGVyKHJ0X2FjYyAhPSAib3RoZXIiKSkKYW5vdmEobWVyMSwgbWVyMiwgbWVyMykKYW5vdmEobWVyMWEsIG1lcjIsIG1lcjMpCmBgYAoKYGBge3J9CnJtKG1lcjEsIG1lcjFhLCBtZXIzKQpgYGAKCkNvbnRyYXN0IG1lYXN1cmVzIGhhdmUgbG93ZXIgYmV0d2VlbiBzdWJqZWN0cyB2YXJpYWJpbGl0eSAoaWUgYXJlIHdvcnNlIGluZGl2aWR1YWwgZGlmZmVyZW5jZSBtZWFzdXJlcykuIFJhdyBhbmQgZGRtIG1lYXN1cmVzIGRvIG5vdCBkaWZmZXIgc2lnbmlmaWNhbnRseS4KCmBgYHtyfQpzdW1tYXJ5KG1lcjIpCmBgYAoKTW9kZWwgdGVzdGluZyBpZiB0aGUgcGVyY2VudGFnZSBvZiByZXNpZHVhbCB2YXJpYW5jZSBvZiByYXcgbWVhc3VyZXMgZGlmZmVycyBmcm9tIHRoYXQgb2YgZGRtIGVzdGltYXRlcyBhbmQgaWYgY29udHJhc3QgbWVhc3VyZXMgZGlmZmVyIGZyb20gbm9uLWNvbnRyYXN0IG1lYXN1cmVzLgoKQ2hlY2tpbmcgaWYgYm90aCBmaXhlZCBlZmZlY3RzIG9mIHJhdyB2cyBkZG0gYW5kIGNvbnRyYXN0IHZzIG5vbi1jb250cmFzdCBhcyB3ZWxsIGFzIHRoZWlyIGludGVyYWN0aW9uIGlzIG5lY2Vzc2FyeS4KCkNvbmNsdXNpb246IEludGVyYWN0aXZlIG1vZGVsIGlzIGJlc3QKCmBgYHtyfQptZXIxID0gbG1lcih2YXJfcmVzaWRfcGN0IH4gZGRtX3JhdyArICgxfGR2KSwgYm9vdF9kZiAlPiUgZmlsdGVyKHJ0X2FjYyAhPSAib3RoZXIiKSkKbWVyMWEgPSBsbWVyKHZhcl9yZXNpZF9wY3QgfiBvdmVyYWxsX2RpZmZlcmVuY2UgKyAoMXxkdiksIGJvb3RfZGYgJT4lIGZpbHRlcihydF9hY2MgIT0gIm90aGVyIikpCm1lcjIgPSBsbWVyKHZhcl9yZXNpZF9wY3QgfiBkZG1fcmF3ICsgb3ZlcmFsbF9kaWZmZXJlbmNlICsgKDF8ZHYpLCBib290X2RmICU+JSBmaWx0ZXIocnRfYWNjICE9ICJvdGhlciIpKQptZXIzID0gbG1lcih2YXJfcmVzaWRfcGN0IH4gZGRtX3JhdyAqIG92ZXJhbGxfZGlmZmVyZW5jZSArICgxfGR2KSwgYm9vdF9kZiAlPiUgZmlsdGVyKHJ0X2FjYyAhPSAib3RoZXIiKSkKYW5vdmEobWVyMSwgbWVyMiwgbWVyMykKYW5vdmEobWVyMWEsIG1lcjIsIG1lcjMpCmBgYAoKYGBge3J9CnJtKG1lcjEsIG1lcjFhLCBtZXIyKQpgYGAKCkJvdGggY29udHJhc3QgYW5kIGNvbmRpdGlvbiBtZWFzdXJlcyBoYXZlIGhpZ2hlciByZXNpZHVhbCB2YXJpYW5jZS4gUmF3IGFuZCBkZG0gbWVhc3VyZXMgZG8gbm90IGRpZmZlci4KCmBgYHtyfQpzdW1tYXJ5KG1lcjMpCmBgYAoKYGBge3J9CnJtKG1lcjMpCmBgYAoKIyMgU2FtcGxlIHNpemUgZWZmZWN0cyBvbiByZWxpYWJpbGl0eQoKRGlmZmVyZW5jZXMgaW4gRERNIHBhcmFtZXRlciByZWxpYWJpbGl0eSBmb3IgdDEgZGF0YSB1c2luZyBlaXRoZXIgbj01NTIgb3Igbj0xNTAgd2VyZSByZXBvcnRlZCBhYm92ZSB1bmRlciBbVDEgSERETSBwYXJhbWV0ZXJzXShodHRwczovL3plbmthdmkuZ2l0aHViLmlvL1NST19ERE1fQW5hbHlzZXMvb3V0cHV0L3JlcG9ydHMvU1JPX0RETV9BbmFseXNlcy5uYi5odG1sI3QxX2hkZG1fcGFyYW1ldGVycykuIE5vIG1lYW5pbmdmdWwgZGlmZmVyZW5jZXMgZXhpc3QgYmV0d2VlbiB0aGVzZSB0d28gc2FtcGxlIHNpemVzLgoKQnV0IGV2ZW4gMTUwIGlzIGEgbGFyZ2Ugc2FtcGxlIHNpemUgZm9yIHBzeWNob2xvZ2ljYWwgc3R1ZGllcywgZXNwZWNpYWxseSBmb3JjZWQgY2hvaWNlIHJlYWN0aW9uIHRpbWUgdGFza3MgdGhhdCBhcmUgaW5jbHVkZWQgaW4gdGhpcyByZXBvcnQuIEhlcmUgd2UgbG9vayBhdCBob3cgdGhlIHJlbGlhYmlsaXR5IGZvciByYXcgYW5kIGRkbSBtZWFzdXJlcyBjaGFuZ2UgZm9yIHNhbXBsZSBzaXplcyB0aGF0IGFyZSBtb3JlIGNvbW1vbiBpbiBzdHVkaWVzIHVzaW5nIHRoZXNlIHRhc2tzICgyNSwgNTAsIDc1LCAxMDAsIDEyNSwgMTUwKQoKKk5vdGU6KiBOb3QgcmVmaXR0aW5nIEhERE0ncyBmb3IgZWFjaCBvZiB0aGVzZSBzYW1wbGUgc2l6ZXMgc2luY2UgYS4gdGhlcmUgd2VyZSBubyBkaWZmZXJlbmNlcyBpbiBwYXJhbWV0ZXIgc3RhYmlsaXR5IGZvciBuPTE1MCB2cyA1NTIgYW5kIGIuIGEgbW9yZSBjb21wcmVoZW5zaXZlIGNvbXBhcmlzb24gdXNpbmcgbm9uLWhpZXJhcmNoaWNhbCBlc3RpbWF0ZXMgYW5kIG1vZGVsIGZpdCBpbmRpY2VzIHdpbGwgZm9sbG93LiAqW1Nob3VsZCBJIHJldmlzaXQgdGhpcz8gLSAxNTAgYW5kIDU1MiBtaWdodCBiZSB0b28gbGFyZ2UgdG8gbGVhZCB0byBjaGFuZ2VzIGluIHBhcmFtZXRlciBlc3RpbWF0ZXMgYnV0IHNtYWxsZXIgc2FtcGxlcyB0aGF0IGFyZSBtb3JlIGNvbW1vbiBpbiBwc3ljaCBzdHVkaWVzIG1pZ2h0IHN3YXkgZXN0aW1hdGVzIG1vcmVdKgoKKk5vdGU6KiBTb21lIHZhcmlhYmxlcyBkbyBub3QgaGF2ZSBlbm91Z2ggdmFyaWFuY2UgdG8gY2FsY3VsYXRlIHJlbGlhYmlsaXR5IGZvciBkaWZmZXJlbmNlIHNhbXBsZSBzaXplcy4gVGhlc2UgdmFyaWFibGVzIGFyZTogIAo+c3Ryb29wLnBvc3RfZXJyb3Jfc2xvd2luZyAgCj5zaW1vbi5zdGRfcnRfZXJyb3IgIAo+c2hhcGVfbWF0Y2hpbmcucG9zdF9lcnJvcl9zbG93aW5nICAKPmRpcmVjdGVkX2ZvcmdldHRpbmcucG9zdF9lcnJvcl9zbG93aW5nICAKPmNob2ljZV9yZWFjdGlvbl90aW1lLnBvc3RfZXJyb3Jfc2xvd2luZyAgCj5jaG9pY2VfcmVhY3Rpb25fdGltZS5zdGRfcnRfZXJyb3IgIAo+ZG90X3BhdHRlcm5fZXhwZWN0YW5jeS5wb3N0X2Vycm9yX3Nsb3dpbmcgIAo+bW90b3Jfc2VsZWN0aXZlX3N0b3Bfc2lnbmFsLmdvX3J0X3N0ZF9lcnJvciAgCj5tb3Rvcl9zZWxlY3RpdmVfc3RvcF9zaWduYWwuZ29fcnRfZXJyb3IgIAo+YXR0ZW50aW9uX25ldHdvcmtfdGFzay5wb3N0X2Vycm9yX3Nsb3dpbmcgIAo+cmVjZW50X3Byb2Jlcy5wb3N0X2Vycm9yX3Nsb3dpbmcgIAo+c2ltb24ucG9zdF9lcnJvcl9zbG93aW5nICAKPmRvdF9wYXR0ZXJuX2V4cGVjdGFuY3kuQllfZXJyb3JzICAKCmBgYHtyfQpzb3VyY2UoJy9Vc2Vycy96ZXluZXBlbmthdmkvRHJvcGJveC9Qb2xkcmFja0xhYi9TUk9fRERNX0FuYWx5c2VzL2NvZGUvd29ya3NwYWNlX3NjcmlwdHMvZGRtX3JlbGRmX3NhbXBsZV9zaXplLlInKQpgYGAKCkRvZXMgdGhlIG1lYW4gcmVsaWFiaWxpdHkgY2hhbmdlIHdpdGggc2FtcGxlIHNpemU/CgpZZXMuIFRoZSBsYXJnZXIgdGhlIHNhbXBsZSBzaXplIHRoZSBtb3JlIHJlbGlhYmxlIGlzIGEgZ2l2ZW4gbWVhc3VyZSBvbiBhdmVyYWdlLiBUaGUgbGFyZ2VzdCBpbmNyZWFzZSBpbiByZWxpYWJpbGl0eSBpcyB3aGVuIHNoaWZ0aW5nIGZyb20gMjUgdG8gNTAgc3ViamVjdHMuIFRoaXMgaXMgaW1wb3J0YW50IGJlY2F1c2UgbWFueSBzdHVkaWVzIHVzaW5nIHRoZXNlIG1lYXN1cmVzIGhhdmUgc2FtcGxlIHNpemVzIDw1MCBwZXIgZ3JvdXAuCgpgYGB7cn0KZmlnX25hbWUgPSAncmVsX2J5X3NhbXBsZXNpemUuanBlZycKCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKHBhc3RlMChmaWdfcGF0aCwgZmlnX25hbWUpKQpgYGAKCldoZW4gPDE1IHN1YmplY3RzIGFyZSB1c2VkIHRvIGNhbGN1bGF0ZSB0aGUgbWVhc3VyZXMgdGhleSBhcmUgc2lnbmlmaWNhbnRseSBsZXNzIHJlbGlhYmxlLgoKYGBge3J9CnN1bW1hcnkobG1lcihpY2MgfiBzYW1wbGVfc2l6ZSArICgxfGR2KSArICgxfGl0ZXJhdGlvbiksIHJlbF9kZl9zYW1wbGVfc2l6ZSkpCmBgYAoKQXJlIHRoZXJlIGRpZmZlcmVuY2VzIGJldHdlZW4gYW55IG90aGVyIHNhbXBsZSBzaXplcz8gVGhpcyBpZ25vcmVzIHRoZSBkaWZmZXJlbmNlcyBiZXR3ZWVuIHZhcmlhYmxlcyBidXQgdGhlcmUgc2VlbXMgdG8gYmUgb25seSBkaWZmZXJlbmNlcyBiZXR3ZWVuIG49MTAgYW5kIGFsbCBvdGhlciBsYXJnZXIgc2FtcGxlIHNpemUuCgpgYGB7cn0Kd2l0aChyZWxfZGZfc2FtcGxlX3NpemVfc3VtbWFyeSwgcGFpcndpc2UudC50ZXN0KG1lYW5faWNjLCBzYW1wbGVfc2l6ZSwgcC5hZGp1c3QubWV0aG9kID0gImJvbmZlcnJvbmkiKSkKYGBgCgpEb2VzIHRoZSBjaGFuZ2UgaW4gcmVsaWFiaWxpaXR5IHdpdGggc2FtcGxlIHNpemUgdmFyeSBieSB2YXJpYWJsZSB0eXBlPwoKVGhlIGNoYW5nZXMgZG8gbm90IGRpZmZlciBieSByYXcgdnMuIGRkbSBtZWFzdXJlcy4gSXQgZG9lcyBkaWZmZXIgYnkgd2hldGhlciB0aGUgbWVhc3VyZSBpcyBhIGNvbnRyYXN0IG1lYXN1cmU6IEZvciBjb250cmFzdCBtZWFzdXJlcyBhbGwgaW5jcmVhc2VzIGluIHJlbGlhYmlsaXR5IHdpdGggc2FtcGxlIHNpemUgYXJlIGxhcmdlciB0aGFuIHRoZSBpbmNyZWFzZXMgZm9yIG5vbi1jb250cmFzdCBtZWFzdXJlcy4gVGhpcyBpbXBsaWVzIHRoYXQgbGFyZ2VyIHNhbXBsZSBzaXplcyBhcmUgZXZlbiBtb3JlIGNydWNpYWwgZm9yIHN0dWRpZXMgdXNpbmcgY29udHJhc3QgbWVhc3VyZXMgYXMgdHJhaXQtbGV2ZWwgbWVhc3VyZXMuCgpgYGB7cn0KdG1wID0gcmVsX2RmX3NhbXBsZV9zaXplICU+JSAKICBncm91cF9ieShzYW1wbGVfc2l6ZSwgZGRtX3Jhdywgb3ZlcmFsbF9kaWZmZXJlbmNlKSAlPiUKICBzdW1tYXJpc2UobWVhbl9pY2MgPSBtZWFuKGljYywgbmEucm09VCksCiAgICAgICAgICAgIHNlbV9pY2MgPSBzZW0oaWNjKSwgCiAgICAgICAgICAgIG1lYW5fdmFyX3N1YnNfcGN0ID0gbWVhbih2YXJfc3Vic19wY3QsIG5hLnJtPVQpLAogICAgICAgICAgICBzZW1fdmFyX3N1YnNfcGN0ID0gc2VtKHZhcl9zdWJzX3BjdCksCiAgICAgICAgICAgIG1lYW5fdmFyX2luZF9wY3QgPSBtZWFuKHZhcl9pbmRfcGN0LCBuYS5ybT1UKSwKICAgICAgICAgICAgc2VtX3Zhcl9pbmRfcGN0ID0gc2VtKHZhcl9pbmRfcGN0KSwKICAgICAgICAgICAgbWVhbl92YXJfcmVzaWRfcGN0ID0gbWVhbih2YXJfcmVzaWRfcGN0LCBuYS5ybT1UKSwKICAgICAgICAgICAgc2VtX3Zhcl9yZXNpZF9wY3QgPSBzZW0odmFyX3Jlc2lkX3BjdCkpICU+JQogIG5hLmV4Y2x1ZGUoKQpgYGAKCmBgYHtyfQpyZWxfZGZfc2FtcGxlX3NpemVfc3VtbWFyeSAlPiUKICBmaWx0ZXIoIWlzLm5hKG92ZXJhbGxfZGlmZmVyZW5jZSkpICU+JQogIGdncGxvdChhZXMoZmFjdG9yKHNhbXBsZV9zaXplKSwgbWVhbl9pY2MpKSsKICBnZW9tX2xpbmUoYWVzKGdyb3VwID0gZHYsIGNvbG9yPWRkbV9yYXcpLCBhbHBoYSA9IDAuMSkrCiAgZ2VvbV9saW5lKGRhdGEgPSB0bXAsIGFlcyhmYWN0b3Ioc2FtcGxlX3NpemUpLG1lYW5faWNjLCBjb2xvcj1kZG1fcmF3LCBncm91cD1kZG1fcmF3KSkrCiAgZ2VvbV9wb2ludChkYXRhID0gdG1wLCBhZXMoZmFjdG9yKHNhbXBsZV9zaXplKSxtZWFuX2ljYywgY29sb3I9ZGRtX3JhdykpKwogIGdlb21fZXJyb3JiYXIoZGF0YSA9IHRtcCxhZXMoeW1pbj1tZWFuX2ljYy1zZW1faWNjLCB5bWF4ID0gbWVhbl9pY2Mrc2VtX2ljYywgY29sb3I9ZGRtX3JhdyksIHdpZHRoID0gMC4xKSsKICBmYWNldF93cmFwKH5vdmVyYWxsX2RpZmZlcmVuY2UpKwogIHlsYWIoIk1lYW4gcmVsaWFiaWxpdHkgb2YgMTAwIHNhbXBsZXMgb2Ygc2l6ZSBuIikrCiAgeGxhYigiU2FtcGxlIHNpemUiKSsKICB0aGVtZShsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpKwogIHlsaW0oLTEsMSkKYGBgCgoKYGBge3J9CnN1bW1hcnkobG1lcihpY2MgfiBzYW1wbGVfc2l6ZSAqIG92ZXJhbGxfZGlmZmVyZW5jZSArICgxfGR2KSArICgxfGl0ZXJhdGlvbiksIHJlbF9kZl9zYW1wbGVfc2l6ZSkpCmBgYAoKRG9lcyB2YXJpYWJpbGl0eSBvZiByZWxpYWJpbGl0eSBjaGFuZ2Ugd2l0aCBzYW1wbGUgc2l6ZT8KCk5vLgoKYGBge3J9CnJlbF9kZl9zYW1wbGVfc2l6ZV9zdW1tYXJ5ICU+JQogIG5hLmV4Y2x1ZGUoKSAlPiUKICBnZ3Bsb3QoYWVzKHNhbXBsZV9zaXplLCBzZW1faWNjKSkrCiAgZ2VvbV9saW5lKGFlcyhncm91cCA9IGR2LCBjb2xvcj1kZG1fcmF3KSwgYWxwaGEgPSAwLjEpKwogIGdlb21fbGluZShkYXRhID0gdG1wLCBhZXMoc2FtcGxlX3NpemUsc2VtX2ljYywgY29sb3I9ZGRtX3JhdykpKwogIGdlb21fcG9pbnQoZGF0YSA9IHRtcCwgYWVzKHNhbXBsZV9zaXplLHNlbV9pY2MsIGNvbG9yPWRkbV9yYXcpKSsKICBmYWNldF93cmFwKH5vdmVyYWxsX2RpZmZlcmVuY2UpKwogIHlsYWIoIlN0YW5kYXJkIGVycm9yIG9mIG1lYW4gb2YgcmVsaWFiaWxpdHkgXG4gb2YgMTAwIHNhbXBsZXMgb2Ygc2l6ZSBuIikrCiAgeGxhYigiU2FtcGxlIHNpemUiKSsKICB0aGVtZShsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpCmBgYAoKYGBge3J9CnN1bW1hcnkobG1lcihzZW1faWNjIH4gc2FtcGxlX3NpemUgKiBvdmVyYWxsX2RpZmZlcmVuY2UgKyAoMXxkdiksIHJlbF9kZl9zYW1wbGVfc2l6ZV9zdW1tYXJ5KSkKYGBgCgpEb2VzIGJldHdlZW4gc3ViamVjdHMgdmFyaWFuY2UgY2hhbmdlIHdpdGggc2FtcGxlIHNpemU/CgpZZXMuIEJldHdlZW4gc3ViamVjdHMgdmFyaWFuY2UgZGVjcmVhc2VzIHdpdGggc2FtcGxlIHNpemUuIFRoaXMgaXMgbW9yZSBwcm9ub3VuY2VkIGZvciBub24tY29udHJhc3QgbWVhc3VyZXMuCgpUaGlzIGdvZXMgYWdhaW5zdCBteSBpbnR1aXRpb25zLiBMb29raW5nIGF0IHRoZSBjaGFuZ2UgaW4gYmV0d2VlbiBzdWJqZWN0cyBwZXJjZW50YWdlIG9mIGluZGl2aWR1YWwgbWVhc3VyZXMnIHRoZXJlIHNlZW1zIHRvIGJlIGEgbG90IG9mIGludGVyLW1lYXN1cmUgdmFyaWFuY2UgKG1vcmUgcHJvbm91bmNlZCBiZWxvdyBmb3Igd2l0aGluIHN1YmplY3QgdmFyaWFuY2UpLiBJJ20gbm90IHN1cmUgaWYgdGhlcmUgaXMgc29tZXRoaW5nIGluIGNvbW1vbiBmb3IgdGhlIG1lYXN1cmVzIHRoYXQgc2hvdyBpbmNyZWFzaW5nIGJldHdlZW4gc3ViamVjdHMgdmFyaWFiaWxpdHkgd2l0aCBzYW1wbGUgc2l6ZSBhbmQgdGhhdCBzZXBhcmF0ZXMgdGhlbSBmcm9tIHRob3NlIHRoYXQgc2hvdyBkZWNyZWFzaW5nIGJldHdlZW4gc3ViamVjdHMgdmFyaWFiaWxpdHkgd2l0aCBzYW1wbGUgc2l6ZSAodGhlIHNsaWdodCBtYWpvcml0eSkuCgpgYGB7cn0KcmVsX2RmX3NhbXBsZV9zaXplX3N1bW1hcnkgJT4lCiAgbmEuZXhjbHVkZSgpICU+JQogIGdncGxvdChhZXMoc2FtcGxlX3NpemUsIG1lYW5fdmFyX3N1YnNfcGN0KSkrCiAgZ2VvbV9saW5lKGFlcyhncm91cCA9IGR2LCBjb2xvcj1kZG1fcmF3KSwgYWxwaGEgPSAwLjEpKwogIGdlb21fbGluZShkYXRhID0gdG1wLCBhZXMoc2FtcGxlX3NpemUsbWVhbl92YXJfc3Vic19wY3QsIGNvbG9yPWRkbV9yYXcpKSsKICBnZW9tX3BvaW50KGRhdGEgPSB0bXAsIGFlcyhzYW1wbGVfc2l6ZSxtZWFuX3Zhcl9zdWJzX3BjdCwgY29sb3I9ZGRtX3JhdykpKwogIGZhY2V0X3dyYXAofm92ZXJhbGxfZGlmZmVyZW5jZSkrCiAgeWxhYigiTWVhbiBwZXJjZW50YWdlIG9mIFxuIGJldHdlZW4gc3ViamVjdHMgdmFyaWFuY2UgXG4gb2YgMTAwIHNhbXBsZXMgb2Ygc2l6ZSBuIikrCiAgeGxhYigiU2FtcGxlIHNpemUiKSsKICB0aGVtZShsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpCmBgYAoKYGBge3J9CnN1bW1hcnkobG1lcih2YXJfc3Vic19wY3QgfiBzYW1wbGVfc2l6ZSAqIG92ZXJhbGxfZGlmZmVyZW5jZSArICgxfGR2KSArICgxfGl0ZXJhdGlvbiksIHJlbF9kZl9zYW1wbGVfc2l6ZSkpCmBgYAoKRG9lcyB3aXRoaW4gc3ViamVjdHMgdmFyaWFuY2UgY2hhbmdlIHdpdGggc2FtcGxlIHNpemU/CgpZZXMuIFRoaXMgYWdhaW4gZ29lcyBhZ2FpbnN0IG15IGludHVpdGlvbiBidXQgaGVyZSB0aGUgaW50ZXItbWVhdXNyZSBkaWZmZXJlbmNlcyBhcmUgZXZlbiBtb3JlIHByb25vdW5jZWQuIFRoZXJlIGFwcGVhcnMgdG8gYmUgc29tZSBtZWFzdXJlcyBmb3Igd2hpY2ggdGhlIGNoYW5nZSBpbiB0d28gbWVhc3VyZW1lbnRzIGF0IGRpZmZlcmVudCB0aW1lIHBvaW50cyBpcyBsYXJnZXIgdGhlIG1vcmUgc3ViamVjdHMgYXJlIHRlc3RlZCBhbmQgdGhvc2UgdGhhdCBzaG93IGEgc21hbGxlciBkZWNyZWFzZSBpbiB3aXRoaW4gc3ViamVjdCB2YXJpYW5jZSB3aXRoIGxhcmdlciBzYW1wbGUgc2l6ZXMuIEkgc3RpbGwgZG9uJ3Qga25vdyBpZiB0aGVzZSB0d28gdHlwZXMgb2YgbWVhc3VyZXMgaGF2ZSBhbnl0aGluZyB0aGF0IGRpc3Rpbmd1aXNoZXMgdGhlbS4KCmBgYHtyfQpyZWxfZGZfc2FtcGxlX3NpemVfc3VtbWFyeSAlPiUKICBuYS5leGNsdWRlKCkgJT4lCiAgZ2dwbG90KGFlcyhzYW1wbGVfc2l6ZSwgbWVhbl92YXJfaW5kX3BjdCkpKwogIGdlb21fbGluZShhZXMoZ3JvdXAgPSBkdiwgY29sb3I9ZGRtX3JhdyksIGFscGhhID0gMC4xKSsKICBnZW9tX2xpbmUoZGF0YSA9IHRtcCwgYWVzKHNhbXBsZV9zaXplLG1lYW5fdmFyX2luZF9wY3QsIGNvbG9yPWRkbV9yYXcpKSsKICBnZW9tX3BvaW50KGRhdGEgPSB0bXAsIGFlcyhzYW1wbGVfc2l6ZSxtZWFuX3Zhcl9pbmRfcGN0LCBjb2xvcj1kZG1fcmF3KSkrCiAgZmFjZXRfd3JhcCh+b3ZlcmFsbF9kaWZmZXJlbmNlKSsKICB5bGFiKCJNZWFuIHBlcmNlbnRhZ2Ugb2YgXG4gd2l0aGluIHN1YmplY3RzIHZhcmlhbmNlIFxuIG9mIDEwMCBzYW1wbGVzIG9mIHNpemUgbiIpKwogIHhsYWIoIlNhbXBsZSBzaXplIikrCiAgdGhlbWUobGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKQpgYGAKCmBgYHtyfQpzdW1tYXJ5KGxtZXIodmFyX2luZF9wY3QgfiBzYW1wbGVfc2l6ZSAqIG92ZXJhbGxfZGlmZmVyZW5jZSArICgxfGR2KSArICgxfGl0ZXJhdGlvbiksIHJlbF9kZl9zYW1wbGVfc2l6ZSkpCmBgYAoKRG9lcyByZXNpZHVhbCB2YXJpYW5jZSBjaGFuZ2Ugd2l0aCBzYW1wbGUgc2l6ZT8KCmBgYHtyfQpyZWxfZGZfc2FtcGxlX3NpemVfc3VtbWFyeSAlPiUKICBuYS5leGNsdWRlKCkgJT4lCiAgZ2dwbG90KGFlcyhzYW1wbGVfc2l6ZSwgbWVhbl92YXJfcmVzaWRfcGN0KSkrCiAgZ2VvbV9saW5lKGFlcyhncm91cCA9IGR2LCBjb2xvcj1kZG1fcmF3KSwgYWxwaGEgPSAwLjEpKwogIGdlb21fbGluZShkYXRhID0gdG1wLCBhZXMoc2FtcGxlX3NpemUsbWVhbl92YXJfcmVzaWRfcGN0LCBjb2xvcj1kZG1fcmF3KSkrCiAgZ2VvbV9wb2ludChkYXRhID0gdG1wLCBhZXMoc2FtcGxlX3NpemUsbWVhbl92YXJfcmVzaWRfcGN0LCBjb2xvcj1kZG1fcmF3KSkrCiAgZmFjZXRfd3JhcCh+b3ZlcmFsbF9kaWZmZXJlbmNlKSsKICB5bGFiKCJNZWFuIHBlcmNlbnRhZ2Ugb2YgcmVzaWR1YWwgdmFyaWFuY2UgXG4gb2YgMTAwIHNhbXBsZXMgb2Ygc2l6ZSBuIikrCiAgeGxhYigiU2FtcGxlIHNpemUiKSsKICB0aGVtZShsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpCmBgYAoKYGBge3J9CnN1bW1hcnkobG1lcih2YXJfcmVzaWRfcGN0IH4gc2FtcGxlX3NpemUgKiBvdmVyYWxsX2RpZmZlcmVuY2UgKyAoMXxkdikgKyAoMXxpdGVyYXRpb24pLCByZWxfZGZfc2FtcGxlX3NpemUpKQpgYGAKCipDb25jbHVzaW9uOiogTGFyZ2VyIHNhbXBsZXMgYXJlIGJldHRlciBmb3IgcmVsaWFiaWxpdHkgYnV0IG5vdCBuZWNlc3NhcmlseSBhbHdheXMgZm9yIHRoZSBzYW1lIHJlYXNvbnM7IGZvciBzb21lIHZhcmlhYmxlcyB0aGlzIGlzIGR1ZSB0byBpbmNyZWFzaW5nIGJldHdlZW4gc3ViamVjdHMgdmFyaWFuY2Ugd2hpbGUgZm9yIG90aGVycyBpdCdzIGR1ZSB0byBkZWNyZWFzaW5nIHJlc2lkdWFsIHZhcmlhbmNlICg/KS4KCmBgYHtyfQpybShyZWxfZGZfc2FtcGxlX3NpemUsIHJlbF9kZl9zYW1wbGVfc2l6ZV9zdW1tYXJ5KQpgYGAKCiMjIEhpZXJhcmNoaWNhbCBlc3RpbWF0aW9uIGNvbnNlcXVlbmNlcwoKVGhlIEggaW4gSERETSBlc3RpbWF0ZXMgc3RhbmRzIGZvciAnaGllcmFyY2hpY2FsJyBkZW5vdGluZyB0aGUgZmFjdCB0aGF0IHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIHdob2xlIHNhbXBsZSBpcyBpbmNvcnBvcnRhdGVkIGluIHRoZSBwcmlvcnMgZm9yIHRoZSBtb2RlbCBwYXJhbWV0ZXJzLiBUaGlzIGlzIGRpZmZlcmVudCB0aGFuIGUuZy4gRVotZGlmZnVzaW9uIHBhcmFtZXRlcnMgdGhhdCB3b3VsZCBiZSB0aGUgc2FtZSBmb3IgYSBnaXZlbiBzdWJqZWN0J3MgZGF0YSByZWdhcmRsZXNzIG9mIHRoZSByZXN0IG9mIHRoZSBzYW1wbGUuIE9uZSBjYW4gYXNrIHdoZXRoZXIgdGhpcyBIIGluZGVlZCBoYXMgYSBtZWFzdXJhYmxlIGltcGFjdC4KCkhERE0gYW5kIEVaIHBhcmFtZXRlciBlc3RpbWF0ZXMgbWlnaHQgZGlmZmVyIGR1ZSB0byBvdGhlciBkaWZmZXJlbmNlIGluIHRoZSBlc3RpbWF0aW9uIHByb2Nlc3MgYXMgd2VsbC4gVGhlcmVmb3JlIHRvIGV2YWx1YXRlIHdoZXRoZXIgdGhlICdIJyBsZWFkcyB0byBtZWFuaW5nZnVsIGNoYW5nZXMgaW4gcGFyYW1ldGVycyB3ZSBjb21wYXJlIHRoZSBzYW1lIG1vZGVscyBmaXQgb24gdGhlIHNhbWUgZGF0YSB1c2luZyBlaXRoZXIgdGhlIHdob2xlIHNhbXBsZSBmb3IgdGhlIGhpZXJhcmNoaWNhbCBzdHJ1Y3R1cmUgb3Igb25seSB0aGUgc2luZ2xlIHN1YmplY3QncyBkYXRhLiBUaGVzZSBsYXR0ZXIgZXN0aW1hdGVzIGFyZSByZWZlcnJlZCB0byBhcyAnZmxhdCcgZXN0aW1hdGVzLgoKYGBge3J9CnJldGVzdF9oZGRtX2ZsYXQgPSByZWFkLmNzdihwYXN0ZTAocmV0ZXN0X2RhdGFfcGF0aCwncmV0ZXN0X2hkZG1fZmxhdC5jc3YnKSkKCnJldGVzdF9oZGRtX2ZsYXQgPSByZXRlc3RfaGRkbV9mbGF0ICU+JSByZW5hbWUoc3ViX2lkID0gc3Vial9pZCkKCnRlc3RfaGRkbV9mbGF0ID0gcmVhZC5jc3YocGFzdGUwKHJldGVzdF9kYXRhX3BhdGgsJy90MV9kYXRhL3QxX2hkZG1fZmxhdC5jc3YnKSkKCnRlc3RfaGRkbV9mbGF0ID0gdGVzdF9oZGRtX2ZsYXQgJT4lIHJlbmFtZShzdWJfaWQgPSBzdWJqX2lkKQoKIyBudW1lcmljX2NvbHMgPSBnZXRfbnVtZXJpY19jb2xzKCkKCiMgQ2hlY2sgaWYgYWxsIHRoZSB2YXJpYWJsZXMgYXJlIHRoZXJlIChubyBmb3Igbm93KQojIHN1bShuYW1lcyhyZXRlc3RfaGRkbV9mbGF0KSAlaW4lIG51bWVyaWNfY29scykgPT0gbGVuZ3RoKG5hbWVzKHJldGVzdF9oZGRtX2ZsYXQpKQojIG5hbWVzKHJldGVzdF9oZGRtX2ZsYXQpW3doaWNoKG5hbWVzKHJldGVzdF9oZGRtX2ZsYXQpICVpbiUgbnVtZXJpY19jb2xzID09IEZBTFNFKV0KCiMgc3VtKG5hbWVzKHRlc3RfaGRkbV9mbGF0KSAlaW4lIG51bWVyaWNfY29scykgPT0gbGVuZ3RoKG5hbWVzKHRlc3RfaGRkbV9mbGF0KSkKIyBuYW1lcyh0ZXN0X2hkZG1fZmxhdClbd2hpY2gobmFtZXModGVzdF9oZGRtX2ZsYXQpICVpbiUgbnVtZXJpY19jb2xzID09IEZBTFNFKV0KYGBgCgojIyMgUGFyYW1ldGVyIGVzdGltYXRlCgpQbG90IHBlcmNlbnQgY2hhbmdlIGluIHJhdyBwYXJhbWV0ZXJzIGZvciByZXRlc3QgYW5kIHQxIGZvciBlYWNoIG9mIDMgcGFyYW1ldGVycyAodXNpbmcgaGllcmFyY2hpY2FsIGFzIGJhc2VsaW5lOiB3aGF0IHBlcmNlbnQgZG9lcyB0aGUgZmxhdCBwYXJhbWV0ZXIgY2hhbmdlIGNvbXBhcmVkIHRvIHRoZSBoaWVyYXJjaGljYWwpCgpGb3IgYm90aCB0aW1lIHBvaW50cyB0aGUgdGhyZXNob2xkcyBhbmQgbm9uLWRlY2lzaW9uIHRpbWVzIGFyZSB2ZXJ5IHNpbWlsYXJ5IHJlZ2FyZGxlc3Mgb2Ygd2hldGhlciB0aGV5IGFyZSBlc3RpbWF0ZWQgaGVpcmFyY2hpY2FsbHkgb3Igd2l0aG91dCB0aGUgaGllcmFyY2h5IChkaWZmZXJlbmNlIHBlYWtpbmcgYXQgMCkuIAoKVGhpcyBpcyBhbHNvIHRydWUgZm9yIHRoZSBtYWpvcml0eSBvZiB0aGUgZHJpZnQgcmF0ZXMuIFRoZXJlIGFyZSwgaG93ZXZlciwgYWxtb3N0IGFzIG1hbnkgZHJpZnQgcmF0ZXMgdGhhdCBjaGFuZ2UgY29tcGxldGVseSB3aGVuIGVzdGltYXRlZCB3aXRob3V0IHRoZSBoaWVyYXJjaHkuICAKCmBgYHtyfQojU2hvdWxkIG5vdCBiZSBuZWNlc3NhcnkgbGF0ZXIKY29tbW9uX2NvbHMgPSBuYW1lcyhyZXRlc3RfaGRkbV9mbGF0KVtuYW1lcyhyZXRlc3RfaGRkbV9mbGF0KSAlaW4lIG5hbWVzKHJldGVzdF9kYXRhKV0KY29tbW9uX2NvbHM9Y29tbW9uX2NvbHNbY29tbW9uX2NvbHMgJWluJSBuYW1lcyh0ZXN0X2hkZG1fZmxhdCldCgpyZXRlc3RfaGRkbV9oaWVyID0gcmV0ZXN0X2RhdGEgJT4lIHNlbGVjdChjb21tb25fY29scykgJT4lIG11dGF0ZShoZGRtPSJoaWVyYXJjaGljYWwiKQp0ZXN0X2hkZG1faGllciA9IHRlc3RfZGF0YSAlPiUgc2VsZWN0KGNvbW1vbl9jb2xzKSAgJT4lIG11dGF0ZShoZGRtPSJoaWVyYXJjaGljYWwiKQpyZXRlc3RfaGRkbV9mbGF0ID0gcmV0ZXN0X2hkZG1fZmxhdCAlPiUgc2VsZWN0KGNvbW1vbl9jb2xzKSAlPiUgbXV0YXRlKGhkZG09ImZsYXQiKQp0ZXN0X2hkZG1fZmxhdCA9IHRlc3RfaGRkbV9mbGF0ICU+JSBzZWxlY3QoY29tbW9uX2NvbHMpICU+JSBtdXRhdGUoaGRkbT0iZmxhdCIpCgpyZXRlc3RfZmxhdF9kaWZmZXJlbmNlID0gcmJpbmQocmV0ZXN0X2hkZG1faGllciwgcmV0ZXN0X2hkZG1fZmxhdCkKcmV0ZXN0X2ZsYXRfZGlmZmVyZW5jZSA9IHJldGVzdF9mbGF0X2RpZmZlcmVuY2UgJT4lCiAgZ2F0aGVyKGR2LCB2YWx1ZSwgLXN1Yl9pZCwgLWhkZG0pICU+JQogIHNwcmVhZChoZGRtLCB2YWx1ZSkgJT4lCiAgbXV0YXRlKGRpZmZfcGN0ID0gKGhpZXJhcmNoaWNhbCAtIGZsYXQpL2hpZXJhcmNoaWNhbCoxMDAsCiAgICAgICAgIGRpZmZfcGN0ID0gaWZlbHNlKGRpZmZfcGN0PCgtMTAwKSwgLTEwMCwgaWZlbHNlKGRpZmZfcGN0PjEwMCwgMTAwLCBkaWZmX3BjdCkpLAogICAgICAgICB0aW1lID0gInJldGVzdCIsCiAgICAgICAgIHBhciA9IGlmZWxzZShncmVwbCgiZHJpZnQiLCBkdiksICJkcmlmdCIsIGlmZWxzZShncmVwbCgidGhyZXNoIiwgZHYpLCAidGhyZXNoIiwgaWZlbHNlKGdyZXBsKCJub25fZGVjaXNpb24iLCBkdiksICJub25fZGVjaXNpb24iLCBOQSkpKSkKCnRlc3RfZmxhdF9kaWZmZXJlbmNlID0gcmJpbmQodGVzdF9oZGRtX2hpZXIsIHRlc3RfaGRkbV9mbGF0KQp0ZXN0X2ZsYXRfZGlmZmVyZW5jZSA9IHRlc3RfZmxhdF9kaWZmZXJlbmNlICU+JQogIGdhdGhlcihkdiwgdmFsdWUsIC1zdWJfaWQsIC1oZGRtKSAlPiUKICBzcHJlYWQoaGRkbSwgdmFsdWUpICU+JQogIG11dGF0ZShkaWZmX3BjdCA9IChoaWVyYXJjaGljYWwgLSBmbGF0KS9oaWVyYXJjaGljYWwqMTAwLAogICAgICAgICBkaWZmX3BjdCA9IGlmZWxzZShkaWZmX3BjdDwoLTEwMCksIC0xMDAsIGlmZWxzZShkaWZmX3BjdD4xMDAsIDEwMCwgZGlmZl9wY3QpKSwKICAgICAgICAgdGltZSA9ICJ0ZXN0IiwKICAgICAgICAgcGFyID0gaWZlbHNlKGdyZXBsKCJkcmlmdCIsIGR2KSwgImRyaWZ0IiwgaWZlbHNlKGdyZXBsKCJ0aHJlc2giLCBkdiksICJ0aHJlc2giLCBpZmVsc2UoZ3JlcGwoIm5vbl9kZWNpc2lvbiIsIGR2KSwgIm5vbl9kZWNpc2lvbiIsIE5BKSkpKQoKZmxhdF9kaWZmZXJlbmNlID0gcmJpbmQodGVzdF9mbGF0X2RpZmZlcmVuY2UsIHJldGVzdF9mbGF0X2RpZmZlcmVuY2UpCgpmbGF0X2RpZmZlcmVuY2UgJT4lCiAgZ2dwbG90KGFlcyhkaWZmX3BjdCkpKwogIGdlb21faGlzdG9ncmFtKCkrCiAgZmFjZXRfZ3JpZChmYWN0b3IodGltZSwgbGV2ZWxzID0gYygidGVzdCIsICJyZXRlc3QiKSxsYWJlbHMgPSBjKCJ0ZXN0IiwgInJldGVzdCIpKSB+IHBhciwgc2NhbGVzPSJmcmVlIikKYGBgCgpJcyB0aGUgYXZlcmFnZSBwZXJjZW50YWdlIGNoYW5nZSBkaWZmZXJlbnQgdGhhbiAwPyBOby4KClRoaXMgbW9kZWwgdXNlcyB0aGUgZGlzdHJpYnV0aW9uIG9mIHBlcmNlbnRhZ2UgZGlmZmVyZW5jZSBpbiBwYXJhbWV0ZXIgZXN0aW1hdGVzIGZvciBkcmlmdCByYXRlcyBhcyB0aGUgYmFzZWxpbmUuIEEgbW9yZSBhcHByb3ByaWF0ZSBtb2RlbCB3b3VsZCB0ZXN0IHdoZXRoZXIgYWxsIHRocmVlIGRpc3RyaWJ1dGlvbnMgYXJlIGRpZmZlcmVudCB0aGFuIDAuIFRoZSBjb25jbHVzaW9uIHNob3VsZCBub3QgY2hhbmdlOiBUaGUgaW50ZXJjZXB0IHN1Z2dlc3RzIHRoYXQgdGhlIG1lYW4gb2YgdGhlIGRyaWZ0IHJhdGUgZGlmZmVyZW5jZSBkaXN0cmlidXRpb24gaXMgYXQgMCBhbmQgdGhpcyBpcyBub3QgZGlmZmVyZW50IHRoYW4gdGhlIGRpc3RyaWJ1dGlvbnMgZm9yIGVpdGhlciBvZiB0aGUgb3RoZXIgcGFyYW1ldGVycyBhbmQgZWl0aGVyIHRpbWUgcG9pbnQuCgpgYGB7cn0Kc3VtbWFyeShsbWVyKGRpZmZfcGN0IH4gdGltZSpwYXIrKDF8ZHYpLCBmbGF0X2RpZmZlcmVuY2UgJT4lIG11dGF0ZShwYXJzID0gZmFjdG9yKHBhciwgbGV2ZWxzID0gYygidGhyZXNoIiwgImRyaWZ0IiwgIm5vbl9kZWNpc2lvbiIpKSkpKQpgYGAKCkRvIHBlb3BsZSBjaGFuZ2UgaW4gdGhlIHNhbWUgd2F5PyBNb3N0bHkuCgpQbG90dGluZyB0aGUgcmF3IHBhcmFtZXRlciBlc3RpbWF0ZSB0aGF0IGlzIGVzdGltYXRlZCBoaWVyYXJjaGljYWxseSBhZ2FpbnN0IHRoZSBlc3RpbWF0ZSB0aGF0IGlzIGVzdGltYXRlZCB3aXRob3V0IHRoZSBoaWVyYXJjaHkuIFJlZCBsaW5lcyBhcmUgdGhlIDQ1LWRlZ3JlZSBsaW5lLiBUaGUgZmFjdCB0aGF0IG1hbnkgcG9pbnRzIGNsdXN0ZXIgYXJvdW5kIHRoaXMgbGluZSBhbmQgdGhhdCB0aGVyZSBhcmUgc3lzdGVtYXRpYyBkZXZpYW5jZXMgZnJvbSBpdCBmb3IgYW55IHBhcmFtZXRlciBhdCBlaXRoZXIgdGltZSBwb2ludCBzdWdnZXN0cyB0aGF0IHRoZSBoaWVyYXJjaGljYWwgYW5kIGZsYXQgZXN0aW1hdGVzIGFyZSBtb3N0bHkgdGhlIHNhbWUuCgpgYGB7cn0KZmxhdF9kaWZmZXJlbmNlICU+JQogIGdncGxvdChhZXMoaGllcmFyY2hpY2FsLCBmbGF0KSkrCiAgZ2VvbV9wb2ludCgpKwogIGdlb21fYWJsaW5lKGFlcyhpbnRlcmNlcHQ9MCwgc2xvcGU9MSksIGNvbG9yPSJyZWQiKSsKICBmYWNldF9ncmlkKGZhY3Rvcih0aW1lLCBsZXZlbHMgPSBjKCJ0ZXN0IiwgInJldGVzdCIpLGxhYmVscyA9IGMoInRlc3QiLCAicmV0ZXN0IikpIH4gcGFyKQpgYGAKCiMjIyBQYXJhbWV0ZXIgcmVsaWFiaWxpdHkKClBsb3R0aW5nIHRoZSByZWxpYWJpbGl0eSBlc3RpbWF0ZXMgZm9yIGZsYXQgcGFyYW1ldGVycyBhZ2FpbnN0IHRoZSByZWxpYWJpbGl0eSBvZiBoaWVyYXJjaGljYWwgZXN0aW1hdGVzLiBSZWQgbGluZXMgYXJlIDQ1LWRlZ3JlZSBsaW5lcy4gV2hpbGUgdGhlcmUgYXJlIHNvbWUgY2hhbmdlcyBpbiByZWxpYWJpbGl0eSBub3RoaW5nIGFwcGVhcnMgdmVyeSBsYXJnZSAob3IgY29uc2VxdWVudGlhbCBpbiBwdXNoaW5nIHRoZSByZWxpYWJpbGl0eSB0byBhbnkgYWNjZXB0YWJsZSBsZXZlbCBkZXBlbmRpbmcgb24gdGhlIGVzdGltYXRpb24gbWV0aG9kKSBvciBzeXN0ZW1hdGljLgoKYGBge3J9CnJlbF9kZl9mbGF0ID0gbWFrZV9yZWxfZGYodDFfZGYgPSB0ZXN0X2hkZG1fZmxhdCwgdDJfZGYgPSByZXRlc3RfaGRkbV9mbGF0LCBtZXRyaWNzID0gYygnaWNjJywgJ3BlYXJzb24nLCAndmFyX2JyZWFrZG93bicpKQoKcmVsX2RmX2ZsYXQgPSByZWxfZGZfZmxhdCAlPiUKICBsZWZ0X2pvaW4ocmVsX2RmWyxjKCJkdiIsICJpY2MiLCAicnRfYWNjIiwgIm92ZXJhbGxfZGlmZmVyZW5jZSIpXSwgYnkgPSAiZHYiKSAKCnJlbF9kZl9mbGF0ICU+JQogIGdncGxvdChhZXMoaWNjLnksIGljYy54KSkrCiAgZ2VvbV9wb2ludCgpKwogIGdlb21fYWJsaW5lKGFlcyhzbG9wZT0xLCBpbnRlcmNlcHQgPSAwKSwgY29sb3I9InJlZCIpKwogIGZhY2V0X3dyYXAofnJ0X2FjYykrCiAgeGxhYigiSGllcmFyY2hpY2FsIHJlbGlhYmlsaXR5IikrCiAgeWxhYigiRmxhdCByZWxpYWJpbGl0eSIpCmBgYAoKYGBge3J9CndpdGgocmVsX2RmX2ZsYXQgJT4lIGZpbHRlcihydF9hY2MgPT0gImRyaWZ0IHJhdGUiKSwgdC50ZXN0KGljYy54LCBpY2MueSwgcGFpcmVkPVQpKQp3aXRoKHJlbF9kZl9mbGF0ICU+JSBmaWx0ZXIocnRfYWNjID09ICJ0aHJlc2hvbGQiKSwgdC50ZXN0KGljYy54LCBpY2MueSwgcGFpcmVkPVQpKQp3aXRoKHJlbF9kZl9mbGF0ICU+JSBmaWx0ZXIocnRfYWNjID09ICJub24tZGVjaXNpb24iKSwgdC50ZXN0KGljYy54LCBpY2MueSwgcGFpcmVkPVQpKQpgYGAKCmBgYHtyfQpybShmbGF0X2RpZmZlcmVuY2UsIHJlbF9kZl9mbGF0LCByZXRlc3RfZmxhdF9kaWZmZXJlbmNlLCByZXRlc3RfaGRkbV9mbGF0LCByZXRlc3RfaGRkbV9oaWVyLCB0ZXN0X2ZsYXRfZGlmZmVyZW5jZSwgIHRlc3RfaGRkbV9mbGF0LCB0ZXN0X2hkZG1faGllcikKYGBgCgojIyMgUGFyYW1ldGVyIGZpdAoKRG8gdGhlIGZpdCBzdGF0aXN0aWNzIGRpZmZlciBieSB3aGV0aGVyIHRoZSBtb2RlbCB3YXMgaGllcmFyY2hpY2FsIG9yIG5vdD8gTm8uCgpgYGB7cn0KdDFfaGllcmFyY2hpY2FsX2ZpdHN0YXRzID0gdDFfaGllcmFyY2hpY2FsX2ZpdHN0YXRzICU+JQogIGZpbHRlcihzdWJqX2lkICVpbiUgcmV0ZXN0X2hpZXJhcmNoaWNhbF9maXRzdGF0cyRzdWJqX2lkKQoKdG1wID0gcmJpbmQocmV0ZXN0X2hpZXJhcmNoaWNhbF9maXRzdGF0cywgcmV0ZXN0X2ZsYXRfZml0c3RhdHMsIHQxX2hpZXJhcmNoaWNhbF9maXRzdGF0cywgdDFfZmxhdF9maXRzdGF0cykgJT4lCiAgc2VwYXJhdGUoc2FtcGxlLCBjKCJ0aW1lIiwgInByb2MiKSwgc2VwPSJfIikgJT4lCiAgc2VsZWN0KGxvZ19yc3FfYWRqLCB0aW1lLCBwcm9jLCBzdWJqX2lkLCB0YXNrX25hbWUpICU+JQogIHNwcmVhZChwcm9jLCBsb2dfcnNxX2FkaikgCgp0bXAgJT4lCiAgZ2dwbG90KGFlcyhoaWVyYXJjaGljYWwsIGZsYXQpKSsKICBnZW9tX3BvaW50KCkrCiAgZ2VvbV9hYmxpbmUoYWVzKHNsb3BlPTEsIGludGVyY2VwdD0wKSwgY29sb3I9InJlZCIpKwogIGZhY2V0X3dyYXAofnRpbWUpCmBgYAoKYGBge3J9CndpdGgodG1wICU+JSBmaWx0ZXIodGltZSA9PSAidDEiKSwgY29yLnRlc3QoZmxhdCwgaGllcmFyY2hpY2FsKSkKd2l0aCh0bXAgJT4lIGZpbHRlcih0aW1lID09ICJyZXRlc3QiKSwgY29yLnRlc3QoZmxhdCwgaGllcmFyY2hpY2FsKSkKYGBgCgoKYGBge3J9CndpdGgodG1wICU+JSBmaWx0ZXIodGltZSA9PSAidDEiKSwgdC50ZXN0KGZsYXQsIGhpZXJhcmNoaWNhbCwgcGFpcmVkPVRSVUUpKQp3aXRoKHRtcCAlPiUgZmlsdGVyKHRpbWUgPT0gInJldGVzdCIpLCB0LnRlc3QoZmxhdCwgaGllcmFyY2hpY2FsLCBwYWlyZWQ9VFJVRSkpCmBgYAoKIyMgQ2x1c3RlcmluZwoKLS0gRG8gRERNIHBhcmFtZXRlcnMgY2FwdHVyZSBzaW1pbGFyIHByb2Nlc3NlcyBhcyB0aGUgcmF3IG1lYXN1cmVzIGluIGEgZ2l2ZW4gdGFzayBvciBkbyB0aGV5IGNhcHR1cmUgcHJvY2Vzc2VzIHRoYXQgYXJlIG1vcmUgc2ltaWxhciBhY3Jvc3MgdGFza3M/CihJZiB0aGUgZm9ybWVyIHRoZXkgd291bGQgYmUgbGVzcyB1c2VmdWwgdGhhbiBpZiB0aGUgbGF0dGVyLikgIAoKVGhpcyBjb3VsZCBiZSBhbmFseXplZCB3aXRoIGZhY3RvciBhbmFseXNpcyBidXQgdGhlcmUgYXJlIG1vcmUgdmFyaWFibGVzIHRoYW4gb2JzZXJ2YXRpb25zIHNvIGFzIGEgZmlyc3QgcGFzcyB3ZSdsbCBleHBsb3JlIGNvcnJlbGF0aW9ucy4gICAgCgpGb3IgdGhpcyB3ZSBjb3JyZWxhdGUgZWFjaCBERE0gbWVhc3VyZSB3aXRoOiAgICAKMS4gcmF3IG1lYXN1cmVzIHdpdGhpbiB0YXNrICAKMi4gb3RoZXIgZGRtIG1lYXN1cmVzIGFjcm9zcyB0YXNrcyAgCgpgYGB7ciBldmFsPUZBTFNFLCBlY2hvPUZBTFNFfQojU3RhbmRhcmRpemUgZGF0YXNldHMKdGVzdF9kYXRhX3N0ZCA9IHRlc3RfZGF0YSAlPiUgbXV0YXRlX2lmKGlzLm51bWVyaWMsIHNjYWxlKQp0ZXN0X2RhdGFfc3RkID0gdGVzdF9kYXRhX3N0ZCAlPiUgc2VsZWN0KC1zdWJfaWQpCgpyZXRlc3RfZGF0YV9zdGQgPSByZXRlc3RfZGF0YSAlPiUgbXV0YXRlX2lmKGlzLm51bWVyaWMsIHNjYWxlKQpyZXRlc3RfZGF0YV9zdGQgPSByZXRlc3RfZGF0YV9zdGQgJT4lIHNlbGVjdCgtc3ViX2lkKQoKI0dldCBjb3JyZWxhdGlvbiB0YWJsZSBmb3IgdGVzdCBkYXRhIGFuZCBtZWx0IGludG8gbG9uZyBmb3JtCnRlc3RfZGF0YV9jb3IgPSBkYXRhLmZyYW1lKGNvcih0ZXN0X2RhdGFfc3RkLCB1c2U9InBhaXJ3aXNlLmNvbXBsZXRlLm9icyIpKQp0ZXN0X2RhdGFfY29yID0gdGVzdF9kYXRhX2NvciAlPiUKICBtdXRhdGUoZHYgPSByb3cubmFtZXMoLikpICU+JQogIGdhdGhlcihrZXksIHZhbHVlLCAtZHYpICU+JQogIGZpbHRlcih2YWx1ZSAhPSAxICYgZHVwbGljYXRlZCh2YWx1ZSk9PUZBTFNFKQoKI0FkZCBtZWFzdXJlIHR5cGUgaW5mbyB0byBsb25nIGZvcm0gY29ycmVsYXRpb24gdGFibGUKdGVzdF9kYXRhX2NvciA9IHRlc3RfZGF0YV9jb3IgJT4lCiAgbGVmdF9qb2luKHJlbF9kZiAlPiUgc2VsZWN0KGR2LCB0YXNrX2dyb3VwLCByYXdfZml0LCBydF9hY2MsIGRkbV9yYXcpLCBieSA9ICJkdiIpICU+JQogIHJlbmFtZSh2YXJfMSA9IGR2LCBkdiA9IGtleSwgdGFza19ncm91cF8xID0gdGFza19ncm91cCwgcmF3X2ZpdF8xID0gcmF3X2ZpdCwgcnRfYWNjXzEgPSBydF9hY2MsIGRkbV9yYXdfMSA9IGRkbV9yYXcpICU+JQogICAgbGVmdF9qb2luKHJlbF9kZiAlPiUgc2VsZWN0KGR2LCB0YXNrX2dyb3VwLCByYXdfZml0LCBydF9hY2MsIGRkbV9yYXcpLCBieSA9ICJkdiIpICU+JQogIHJlbmFtZSh2YXJfMiA9IGR2LCB0YXNrX2dyb3VwXzIgPSB0YXNrX2dyb3VwLCByYXdfZml0XzIgPSByYXdfZml0LCBydF9hY2NfMiA9IHJ0X2FjYywgZGRtX3Jhd18yID0gZGRtX3JhdykgJT4lCiAgI3Rhc2stdGFzazogaWYgdGhlIG1lYXN1cmVzIGFyZSBmcm9tIHRoZSBzYW1lIHRhc2sgYW5kIG9uZSBvZiB0aGVtIGlzIGEgZGRtIG1lYXN1cmUgd2hpbGUgdGhlIG90aGVyIGlzIHJhdwogICNkZG0tZGRtOiBpZiB0aGUgbWVhc3VyZXMgYXJlIE5PVCBmcm9tIHRoZSBzYW1lIHRhc2sgYW5kIHRoZXkgYXJlIGJvdGggZGRtIG1lYXN1cmVzCiAgbXV0YXRlKHRhc2tfdGFzayA9IGlmZWxzZSgodGFza19ncm91cF8xID09IHRhc2tfZ3JvdXBfMikgJiAoKGRkbV9yYXdfMSA9PSAiZGRtIiAmIGRkbV9yYXdfMiA9PSAicmF3IikgfCAoZGRtX3Jhd18xID09ICJyYXciICYgZGRtX3Jhd18yID09ICJkZG0iKSksICJ0YXNrLXRhc2siLCBpZmVsc2UoKHRhc2tfZ3JvdXBfMSAhPSB0YXNrX2dyb3VwXzIpICYgKGRkbV9yYXdfMSA9PSAiZGRtIiAmIGRkbV9yYXdfMiA9PSAiZGRtIiksICJkZG0tZGRtIixOQSkpLCAKICAgICAgICAgdGltZT0idGVzdCIpCgojc3VtbWFyaXNlIGJ5IHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGNvcnJlbGF0ZWQgdmFyaWFibGVzIGZvciBwbG90dGluZwp0ZXN0X2RhdGFfY29yX21lZCA9IHRlc3RfZGF0YV9jb3IgJT4lCiAgbmEuZXhjbHVkZSgpICU+JQogIGdyb3VwX2J5KHRhc2tfdGFzaykgJT4lCiAgc3VtbWFyaXNlKG1lZGlhbl9hYnNfY29yID0gbWVkaWFuKGFicyh2YWx1ZSkpLAogICAgICAgICAgICBtZWFuX2Fic19jb3IgPSBtZWFuKGFicyh2YWx1ZSkpLAogICAgICAgICAgICB0aW1lPSJ0ZXN0IikKCiNHZXQgc2FtZSBjb3JyZWxhdGlvbiB0YWJsZSBmb3IgcmV0ZXN0IGRhdGEKcmV0ZXN0X2RhdGFfY29yID0gZGF0YS5mcmFtZShjb3IocmV0ZXN0X2RhdGFfc3RkLCB1c2U9InBhaXJ3aXNlLmNvbXBsZXRlLm9icyIpKQpyZXRlc3RfZGF0YV9jb3IgPSByZXRlc3RfZGF0YV9jb3IgJT4lCiAgbXV0YXRlKGR2ID0gcm93Lm5hbWVzKC4pKSAlPiUKICBnYXRoZXIoa2V5LCB2YWx1ZSwgLWR2KSAlPiUKICBmaWx0ZXIodmFsdWUgIT0gMSAmIGR1cGxpY2F0ZWQodmFsdWUpPT1GQUxTRSkKCnJldGVzdF9kYXRhX2NvciA9IHJldGVzdF9kYXRhX2NvciAlPiUKICBsZWZ0X2pvaW4ocmVsX2RmICU+JSBzZWxlY3QoZHYsIHRhc2tfZ3JvdXAsIHJhd19maXQsIHJ0X2FjYywgZGRtX3JhdyksIGJ5ID0gImR2IikgJT4lCiAgcmVuYW1lKHZhcl8xID0gZHYsIGR2ID0ga2V5LCB0YXNrX2dyb3VwXzEgPSB0YXNrX2dyb3VwLCByYXdfZml0XzEgPSByYXdfZml0LCBydF9hY2NfMSA9IHJ0X2FjYywgZGRtX3Jhd18xID0gZGRtX3JhdykgJT4lCiAgICBsZWZ0X2pvaW4ocmVsX2RmICU+JSBzZWxlY3QoZHYsIHRhc2tfZ3JvdXAsIHJhd19maXQsIHJ0X2FjYywgZGRtX3JhdyksIGJ5ID0gImR2IikgJT4lCiAgcmVuYW1lKHZhcl8yID0gZHYsIHRhc2tfZ3JvdXBfMiA9IHRhc2tfZ3JvdXAsIHJhd19maXRfMiA9IHJhd19maXQsIHJ0X2FjY18yID0gcnRfYWNjLCBkZG1fcmF3XzIgPSBkZG1fcmF3KSAlPiUKICBtdXRhdGUodGFza190YXNrID0gaWZlbHNlKCh0YXNrX2dyb3VwXzEgPT0gdGFza19ncm91cF8yKSAmICgoZGRtX3Jhd18xID09ICJkZG0iICYgZGRtX3Jhd18yID09ICJyYXciKSB8IChkZG1fcmF3XzEgPT0gInJhdyIgJiBkZG1fcmF3XzIgPT0gImRkbSIpKSwgInRhc2stdGFzayIsIGlmZWxzZSgodGFza19ncm91cF8xICE9IHRhc2tfZ3JvdXBfMikgJiAoZGRtX3Jhd18xID09ICJkZG0iICYgZGRtX3Jhd18yID09ICJkZG0iKSwgImRkbS1kZG0iLE5BKSksCiAgICAgICAgIHRpbWU9InJldGVzdCIpCgpyZXRlc3RfZGF0YV9jb3JfbWVkID0gcmV0ZXN0X2RhdGFfY29yICU+JQogIG5hLmV4Y2x1ZGUoKSAlPiUKICBncm91cF9ieSh0YXNrX3Rhc2spICU+JQogIHN1bW1hcmlzZShtZWRpYW5fYWJzX2NvciA9IG1lZGlhbihhYnModmFsdWUpKSwKICAgICAgICAgICAgbWVhbl9hYnNfY29yID0gbWVhbihhYnModmFsdWUpKSwgCiAgICAgICAgICAgIHRpbWUgPSAicmV0ZXN0IikKCmFsbF9kYXRhX2NvciA9IHJiaW5kKHRlc3RfZGF0YV9jb3IsIHJldGVzdF9kYXRhX2NvcikKYWxsX2RhdGFfY29yX21lZCA9IHJiaW5kKHRlc3RfZGF0YV9jb3JfbWVkLCByZXRlc3RfZGF0YV9jb3JfbWVkKQoKYWxsX2RhdGFfY29yICU+JQogIG5hLmV4Y2x1ZGUoKSAlPiUKICBnZ3Bsb3QoYWVzKGFicyh2YWx1ZSkpKSsKICBnZW9tX2hpc3RvZ3JhbSgpKwogIGdlb21fdmxpbmUoZGF0YT1hbGxfZGF0YV9jb3JfbWVkLCBhZXMoeGludGVyY2VwdD1tZWRpYW5fYWJzX2NvciksIGNvbG9yPSJyZWQiLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSsKICBmYWNldF9ncmlkKHRpbWV+dGFza190YXNrKSsKICB4bGFiKCJBYnNvbHV0ZSBjb3JyZWxhdGlvbiIpCmBgYAoKKEFic29sdXRlKSBjb3JyZWxhdGlvbnMgYmV0d2VlbiByYXcgYW5kIGRkbSBtZWFzdXJlcyB3aXRoaW4gYSB0YXNrIGFyZSBoaWdoZXIgdGhhbiB0aG9zZSBiZXR3ZWVuIGRkbSBtZWFzdXJlcyBhY3Jvc3MgdGFza3MuCgpgYGB7ciAgZXZhbD1GQUxTRSwgZWNobz1GQUxTRX0KYWxsX2RhdGFfY29yX21lZApgYGAKCmBgYHtyICBldmFsPUZBTFNFLCBlY2hvPUZBTFNFfQpybShhbGxfZGF0YV9jb3IsIGFsbF9kYXRhX2Nvcl9tZWQsIHJldGVzdF9kYXRhX2NvciwgcmV0ZXN0X2RhdGFfY29yX21lZCwgdGVzdF9kYXRhX2NvciwgdGVzdF9kYXRhX2Nvcl9tZWQpCmBgYAoKRmFjdG9yIGFuYWx5c2lzCgpgYGB7cn0KCmBgYAoKLS0gQXJlIHRoZXNlIGNsdXN0ZXJzIG1vcmUgcmVsaWFibGUgdGhhbiB1c2luZyBlaXRoZXIgdGhlIHJhdyBvciB0aGUgRERNIG1lYXN1cmVzIGFsb25lPwoKIyMgUHJlZGljdGlvbgoKLS0gRG8gcmF3IG9yIERETSBtZWFzdXJlcyAob3IgZmFjdG9yIHNjb3JlcykgcHJlZGljdCByZWFsIHdvcmxkIG91dGNvbWVzIGJldHRlcj8KCiMjIFRvIERvCgotIEFsdGVybmF0ZSBERE1zICAKLSBUaW1lIGFuZCBhY2N1cmFjeSBjb3N0cyB2cyBERE1zIChIZWRnZSBldCBhbCwgMjAxOCwgUHN5Y2ggQnVsbCkgIAotIFRyaWFsIGJ5IHRyaWFsIHZhcmlhYmlsaXR5IGFzIGluZGl2aWR1YWwgZGlmZmVyZW5jZSBtZWFzcmVzIChSb3VkZXIgYW5kIEhhYWYsIHBzeUFyWGl2KSAg